Re-exploration of Value Semantic and Pointer Semantic in Golang

136 阅读1分钟

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.

  1. 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}]
  1. 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}]
  1. 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}]
  1. 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}]