golang another func change map of a struct

huangapple go评论113阅读模式
英文:

golang another func change map of a struct

问题

我是你的中文翻译助手,以下是翻译好的内容:

我是一个新手,现在有一个关于函数传递变量的问题。以下是代码:

  1. type User struct {
  2. Name string
  3. Map map[string]string
  4. }
  5. func main() {
  6. u := User{Name: "Leto"}
  7. u.Map = make(map[string]string)
  8. fmt.Println("before --------")
  9. fmt.Println(unsafe.Pointer(&u))
  10. fmt.Println(unsafe.Pointer(&(u.Map)))
  11. fmt.Println(u)
  12. Modify(u)
  13. fmt.Println("after --------")
  14. fmt.Println(u)
  15. }
  16. func Modify(u User) {
  17. fmt.Println("in func --------")
  18. fmt.Println(unsafe.Pointer(&u))
  19. fmt.Println(unsafe.Pointer(&(u.Map)))
  20. u.Name = "Paul"
  21. u.Map["t"] = "t"
  22. }

上述代码的输出结果为:

  1. before --------
  2. 0xc04203a4c0
  3. 0xc04203a4d0
  4. {Leto map[]}
  5. in func --------
  6. 0xc04203a500
  7. 0xc04203a510
  8. after --------
  9. {Leto map[t:t]}

Modify函数中,我知道User是一个副本,所以更改Name不起作用是可以理解的,但为什么更改Map会影响到外部的User结构呢?

英文:

I'm a new one on go.Now I have a question about functoin pass variable.Here is the code:

  1. type User struct {
  2. Name string
  3. Map map[string]string
  4. }
  5. func main() {
  6. u := User{Name: "Leto"}
  7. u.Map = make(map[string]string)
  8. fmt.Println("before --------")
  9. fmt.Println(unsafe.Pointer(&u))
  10. fmt.Println(unsafe.Pointer(&(u.Map)))
  11. fmt.Println(u)
  12. Modify(u)
  13. fmt.Println("after --------")
  14. fmt.Println(u)
  15. }
  16. func Modify(u User) {
  17. fmt.Println("in func --------")
  18. fmt.Println(unsafe.Pointer(&u))
  19. fmt.Println(unsafe.Pointer(&(u.Map)))
  20. u.Name = "Paul"
  21. u.Map["t"] = "t"
  22. }

code above output:

  1. before --------
  2. 0xc04203a4c0
  3. 0xc04203a4d0
  4. {Leto map[]}
  5. in func --------
  6. 0xc04203a500
  7. 0xc04203a510
  8. after --------
  9. {Leto map[t:t]}

in Modify func i know user is a copy ,so change name not work is ok ,but why change Map effect out user struct ?

答案1

得分: 0

我们需要了解每次调用时内存分配的工作原理:

  1. u := User{Name: "Leto"}
  2. // u 是 User 类型的对象
  3. // 在这行代码之后,内存已经分配给了 u.Name(字符串类型)和 u.Map(引用类型)的属性
  4. // 假设 u.Name 的分配内存地址以 x 开头
  5. // u.Map 的分配内存地址以 y 开头,并且请注意,u.Map 是一个引用,即它所包含的值将是一个不同的内存地址,该地址将是实际 map 的起始内存地址
  6. // 此时,y 处的值为 nil,因为它没有指向任何内存地址
  7. u.Map = make(map[string]string)
  8. // 现在,y 的值已更新为 z(这是使用 make 调用初始化的 map 的起始内存地址)
  9. fmt.Println("before --------")
  10. fmt.Println(unsafe.Pointer(&u))
  11. fmt.Println(unsafe.Pointer(&(u.Map)))
  12. fmt.Println(u)
  13. // 在这里,您将通过值传递对象
  14. // 因此,基本上会创建一个新的 User 类型的对象副本
  15. // u.Name 的副本将有一个新的地址
  16. // 让我们称之为 x1,并且值 "Leto" 也将被复制到以 x1 开头的内存地址
  17. // u.Map 的副本也将有一个新的地址,让我们称之为 y1,并且它的值 z 也将被复制到以 y1 开头的内存地址
  18. // 我想您现在已经得到了答案。
  19. // 基本上,新复制的对象的属性 u.Map 和旧对象的 u.Map 都指向相同的内存地址 "z",因此无论哪个对象更新了 map,另一个对象都会看到它
  20. Modify(u)
  21. fmt.Println("after --------")
  22. fmt.Println(u)
英文:

We need to understand how memory allocation is working here in each call:

  1. u := User{Name: "Leto"}
  2. // u is an object of type User
  3. // after this line memory has been allocated to both the
  4. // properties u.Name(string) and u.Map(reference)
  5. // lets say allocated memory address for u.Name starts with x
  6. // for u.Map it starts with y, and note that u.Map is a reference i.e.
  7. // the value contained in it will be a different memory address which
  8. // will be the starting memory address of the actual map
  9. // right now the value written at y is nil since it
  10. // does not point to any memory address
  11. u.Map = make(map[string]string)
  12. // now value of y has been updated to z (which is the
  13. // memory address of the beginning of the map initialized
  14. // with make call)
  15. fmt.Println("before --------")
  16. fmt.Println(unsafe.Pointer(&u))
  17. fmt.Println(unsafe.Pointer(&(u.Map)))
  18. fmt.Println(u)
  19. // here you are about to pass object by value
  20. // so basically a new object will be created of type User
  21. // lets talk about how copy of this object will be created
  22. // copy of u.Name will have a new address
  23. // lets call it x1 and the value "Leto" too will be
  24. // copied to memory address starting with x1
  25. // copy of u.Map will have a new address too lets call it
  26. // y1 and its value z will be copied too to the memory address y1
  27. // I think you must have got your answer by now.
  28. // Basically the newly copied object's property u.Map and
  29. // the old one's u.Map both points to the same memory address "z"
  30. // and hence whosoever updates the map the other one will see it
  31. Modify(u)
  32. fmt.Println("after --------")
  33. fmt.Println(u)

答案2

得分: -1

你应该在赋值和修改操作中分别使用 &User 和 *User。

请查看此链接:https://play.golang.org/p/tDh1JBpK-t

使用指向结构体的指针总是更好的选择。

英文:

You should use &User and *User respectively in your assignment and modify operations.

Check this https://play.golang.org/p/tDh1JBpK-t

Its always better to work with pointers to structs.

答案3

得分: -3

切片(Slices)、映射(Maps)和通道(Channels)都是引用类型,因此它们总是通过引用传递。

英文:

Slices, maps and channels are reference types. so they are always passed by reference.

huangapple
  • 本文由 发表于 2016年11月10日 12:43:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/40520099.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定