传递值时与通过引用传递时地图的奇怪突变(Golang)

Strange mutation of map when passed value vs when passed by reference (Golang)

第一种情况中,我按值将地图传递给: 主包

import (
    "fmt"
    "time"
)

func timeMap(z map[string]interface{}) {
    z["updated_at"] = time.Now()
}

func main() {
    foo := map[string]interface{}{
        "Matt": 42,
    }
    timeMap(foo)
    fmt.Println(foo)
}

输出为静音贴图:

map[updated_at:2009-11-10 23:00:00 +0000 UTC Matt:42]

第二种情况中,代码几乎相同,但通过引用传递:

package main

import (
    "fmt"
    "time"
)

func timeMap(z *map[string]interface{}) {
    (*z)["updated_at"] = time.Now()
}

func main() {
    foo := map[string]interface{}{
        "Matt": 42,
    }
    timeMap(&foo)
    fmt.Println(foo)
}

显然,结果不同:

map[Matt:42 updated_at:2009-11-10 23:00:00 +0000 UTC]

我的期望如下:

为什么会这样?

Go 中没有引用传递这回事。每当你传递任何东西(指针、切片 header、地图)时,它总是按值传递。问题是究竟什么是按值传递的(即类型的实际 value 是什么)。

当你传递一个映射时,你将指针的副本传递给它的header,其中包含一组指向桶的指针,如在实现中哈希表。 https://github.com/golang/go/blob/master/src/runtime/hashmap.go#L106

因此,将指针传递给地图几乎没有意义,因为复制地图 header 指针的操作非常便宜。

为什么顺序不同,这仅仅是由于地图的内部实现,以随机方式遍历键。同样,这只是一个实现细节。

编辑:

正如@icza 正确指出的那样,传递地图实际上是将 指针 的副本传递给地图 header,而不是地图 header本身。抱歉造成混淆