In the previous article, I explained the difference between value semantic and pointer semantic, now in this article, i want to explain this combined with value or pointer receiver to see what's happening when value and pointer semantic is used in different context.
- value semantic of for-range and methods with value receiver
package main
import (
"fmt"
)
type user struct {
email string
}
func (u user) changeEmail(email string) {
u.email = email
}
func main() {
users := []user{
{"e1"},
{"e2"},
}
fmt.Println(users)
for _, u := range users {
u.changeEmail("new")
}
fmt.Println(users)
}
Struct in Golang is value type, although users is slice type, the underlying copied data of for-range is also slice type, but changeEmail only modifies the copy of u in for-range, not u itself.
[{e1} {e2}]
[{e1} {e2}]
- value semantic of for-range and methods with pointer receiver
package main
import (
"fmt"
)
type user struct {
email string
}
func (u *user) changeEmail(email string) {
u.email = email
}
func main() {
users := []user{
{"e1"},
{"e2"},
}
fmt.Println(users)
for _, u := range users {
u.changeEmail("new")
}
fmt.Println(users)
}
Although changeEmail has a pointer type as its receiver, the u in for-range is also a new copy of users, so the underlying items of users does not change at all.
[{e1} {e2}]
[{e1} {e2}]
- pointer semantic and methods with value receiver
package main
import (
"fmt"
)
type user struct {
email string
}
func (u user) changeEmail(email string) {
u.email = email
}
func main() {
users := []user{
{"e1"},
{"e2"},
}
fmt.Println(users)
for i := range users {
users[i].changeEmail("new")
}
fmt.Println(users)
}
Now the for-range has pointer semantic, but changeEmail has value receiver, so the underlying items of users does not change, too.
[{e1} {e2}]
[{e1} {e2}]
- pointer semantic and methods with pointer receiver
package main
import (
"fmt"
)
type user struct {
email string
}
func (u *user) changeEmail(email string) {
u.email = email
}
func main() {
users := []user{
{"e1"},
{"e2"},
}
fmt.Println(users)
for i := range users {
users[i].changeEmail("new")
}
fmt.Println(users)
}
As expected, now the items of users has changed because changeEmail has pointer receiver and the for-range has pointer semantic, the original item of users is changed in this case.
[{e1} {e2}]
[{new} {new}]