As Cerise mentioned, the 'USP' of methods is the fact that they are tied to interfaces and let you write 'object-oriented' code (for sake of completeness, struct embedding also lets you write 'object-oriented' code).
Taking the classic Stringer interface as an example, your 'Person' type can implement the Stringer interface merely by implementing a String() method. See this code example: https://tour.golang.org/methods/17
Now, the reason to do it this way (instead of writing a function) is that any instance of the 'Person' type can now be passed as an argument to code that accepts Stringer as input. To take a highly simplified example, let's assume there is some function in some library which provides some very complex behaviour which you need to call. But this function accepts args of type Stringer:
func SomeComplexFunction (s Stringer) {
//some complex code
}
If 'Person' implements String(), you can pass instances of Person to this hypothetical function
p1 := Person{“satish”, 23}
SomeComplexFunction(p1)
The complex function is obviously not aware of your Person type, but can work with it due to the fact that Person implements the Stringer interface (by implementing Stringer's methods). In some cases, you could achieve the same by passing function as arguments ('C' style function pointers)... but the code complexity can go up a bit in doing so.
To take a more 'real-world' example, let's say you had types representing different products in a store and a Shipment Processor to handle shipments. To avoid having to change your shipment code every time you add a new product, you're best off using an interface (with methods) to provide this abstraction.
type MobilePhone struct {
//fields
}
func (o *MobilePhone) GetWeight() float64 {
//return the product's weight
}
type Toy struct {
//fields
}
func (o *Toy) GetWeight() float64 {
//return the product's weight
}
type IShippable interface {
GetWeight() float64
//other shipment related methods
}
ShipmentProcessort(shipment IShippable) {
//code to process shipment
}