func (p *person) changeName(name string) { p.name = name // `(*p).name = name` is also valid, but unnecessary in Go.}func main() { user := person{name: "John", age: 35} user.sayHello() // Hello, my name is John user.changeName("Jane") user.sayHello() // Hello, my name is Jane}
Go automatically dereferences struct pointers (T to *T) when accessing fields. This is why p.name = name can be used instead of (*p).name = name.
The automatic T to *T conversion only happens when the value is addressable.
A value is addressable if it has a stable memory location.
type person struct { name string}func (p *person) sayHello() { fmt.Println("Hello, my name is", p.name)}func main() { user := person{name: "John"} user.sayHello() // Hello, my name is John person{name: "John"}.sayHello() // <-- compiler: cannot call pointer method sayHello on person}
user is a variable with a stable address. The compiler can take &user implicitly.
person{name: "John"} is a temporary value without a stable address. The compiler cannot take its address, so the call does not compile.
To make it work, take the address explicitly:
(&person{name: "John"}).sayHello() // Hello, my name is John
Embedded structs with methods.
Methods from an embedded struct are also promoted to the outer struct and can be called directly.
type person struct { name string age int}func (p person) sayHello() { fmt.Println("Hello, my name is", p.name)}type employee struct { person company string}func main() { user := person{name: "John", age: 35} user.sayHello() // Hello, my name is John user2 := employee{person{name: "Jane", age: 28}, "Google"} user2.sayHello() // Hello, my name is Jane}
If the outer struct defines a method with the same name, that method is used instead of the promoted one. The embedded method is shadowed but can still be accessed through the embedded field.
func (e employee) sayHello() { fmt.Println("Hello, my name is", e.name, "and I'm working at", e.company)}func main() { user := person{name: "John", age: 35} user.sayHello() // Hello, my name is John user2 := employee{person{name: "Jane", age: 28}, "Google"} user2.sayHello() // Hello, my name is Jane and I'm working at Google user2.person.sayHello() // Hello, my name is Jane}