0

Why does map have different behavior on Go?

All types in Go are copied by value: string, intxx, uintxx, floatxx, struct, [...]array, []slice except for map[key]value

package main

import "fmt"
type test1 map[string]int

func (t test1) DoSomething() { // doesn't need to use pointer
   t["yay"] = 1
}

type test2 []int

func (t* test2) DoSomething() { // must use pointer so changes would effect
    *t = append(*t,1)
}

type test3 struct{
    a string
    b int
}

func (t* test3) DoSomething() { // must use pointer so changes would effect
    t.a = "aaa"
    t.b = 123
}

func main() {
 t1 := test1{}
 u1 := t1
 u1.DoSomething()
 fmt.Println("u1",u1)
 fmt.Println("t1",t1)

 t2 := test2{}
 u2 := t2
 u2.DoSomething()
 fmt.Println("u2",u2)
 fmt.Println("t2",t2)

 t3 := test3{}
 u3 := t3
 u3.DoSomething()
 fmt.Println("u3",u3)
 fmt.Println("t3",t3)
}

And passing variable as function's parameter/argument is equal to assignment with :=

package main

import "fmt"
type test1 map[string]int

func DoSomething1(t test1)  { // doesn't need to use pointer
   t["yay"] = 1
}

type test2 []int

func DoSomething2(t *test2) { // must use pointer so changes would effect
    *t = append(*t,1)
}

type test3 struct{
    a string
    b int
}

func DoSomething3(t *test3) { // must use pointer so changes would effect
    t.a = "aaa"
    t.b = 123
}

func main() {
 t1 := test1{}
 DoSomething1(t1)
 fmt.Println("t1",t1)

 t2 := test2{}
 DoSomething2(&t2)
 fmt.Println("t2",t2)

 t3 := test3{}
 DoSomething3(&t3)
 fmt.Println("t3",t3)
}
Rick-777
  • 9,714
  • 5
  • 34
  • 50
Kokizzu
  • 24,974
  • 37
  • 137
  • 233

1 Answers1

3

Map values are pointers. Some other types (slice, string, channel, function) are, similarly, implemented with pointers. Interestingly, the linked FAQ entry says,

Early on, maps and channels were syntactically pointers and it was impossible to declare or use a non-pointer instance. ... Eventually we decided that the strict separation of pointers and values made the language harder to use.

"Go passes by value" means variables passed as regular function args won't be modified by the called function. That doesn't change that some built-in types can contain pointers (just like your own structs can).

Python is similar: f(x) won't change an integer x passed to it, but it can append to a list x because Python lists are implemented with a pointer internally. C++, by contrast, has actual pass-by-reference available: f(x) can change the caller's int x if f is declared to have a reference parameter (void f(int& x)).

(I also wrote some general info on pointers vs. values in Go in an answer to another question, if that helps.)

Community
  • 1
  • 1
twotwotwo
  • 28,310
  • 8
  • 69
  • 56