Methods
suggest changeA method is a function tied to a type, usually a struct but it works with any type.
This is similar to classes in languages like Java or C++.
Basics of methods:
type Person struct {
FirstName string
LastName string
}
func (p *Person) PrintFullName() {
fmt.Printf("%s %s\n", p.FirstName, p.LastName)
}
func main() {
p := &Person{
"John",
"Doe",
}
p.PrintFullName()
}
John Doe
The instance on which the method operates is called a receiver.
In the above example method PrintFullName
takes a receiver p
whose type is *Person
.
People coming from other languages are tempted to name the receiver this
(mimicking C++) or self
(mimicking Python). That is bad style in Go.
In Go, the rule for naming receiver is:
- be short (usually a single letter)
- be the same for all methods
Value vs. pointer receiver
Method receiver can be either a value or a pointer.
As a convenience, the Go allows calling a pointer receiver on a value and calling a value receiver on a pointer:
type Person struct {
FirstName string
LastName string
}
func (p Person) PrintFullNameValue() {
fmt.Printf("PrintFullNameValue: address of p is %p\n", &p)
}
func (p *Person) PrintFullNamePointer() {
fmt.Printf("PrintFullNamePointer: p is %p\n", p)
}
func main() {
p := Person{
"John",
"Doe",
}
fmt.Printf("address of p: %p\n", &p)
p.PrintFullNamePointer()
p.PrintFullNameValue()
pp := &p
fmt.Printf("\naddress of pp: %p\n", pp)
pp.PrintFullNamePointer()
pp.PrintFullNameValue()
}
address of p: 0xc00000c060
PrintFullNamePointer: p is 0xc00000c060
PrintFullNameValue: address of p is 0xc00000c080
address of pp: 0xc00000c060
PrintFullNamePointer: p is 0xc00000c060
PrintFullNameValue: address of p is 0xc00000c0a0
A value receiver is called on a copy of a value:
type Foo struct {
Str string
}
func (f Foo) Print() {
fmt.Printf("Value of Str inside Print: '%s'\n", f.Str)
fmt.Printf("Address of &f inside Print: 0x%p\n", &f)
f.Str = "changed"
}
func main() {
fv := Foo{
Str: "Foo",
}
fv.Print()
fmt.Printf("Address of &fv before Print: 0x%p\n", &fv);
fmt.Printf("Value of Str after Print: '%s'\n", fv.Str)
}
Value of Str inside Print: 'Foo'
Address of &f inside Print: 0x0xc000010220
Address of &fv before Print: 0x0xc000010210
Value of Str after Print: 'Foo'
You can see above the consequences of calling value receiver on a copy of a value:
- the address of
f
receiver is different that the address offv
value. This indicates it's a different value i.e.f
is a copy offv
that Go compiler created implicilty - changing
f
insidePrint
value receiver doesn't change thefv
value