Are maps passed by value or by reference in Go?

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

Are maps passed by value or by reference in Go?

问题

在Go语言中,地图(maps)是通过引用传递的。这意味着当你将地图作为参数传递给函数时,实际上是传递了指向地图的指针,而不是地图的副本。因此,对地图的任何修改都会影响到原始地图。

对于返回值,你可以选择返回地图的指针或者将地图作为值返回。如果你返回地图的指针,那么调用者将可以直接修改地图的内容。如果你返回地图作为值,那么调用者将得到地图的副本,对副本的修改不会影响到原始地图。

关于性能方面的考虑,如果地图较大,且你希望避免不必要的数据复制,那么返回地图的指针可能更高效。但是需要注意的是,返回指针也意味着调用者可能会修改原始地图的内容,这可能会引入潜在的并发问题。

总的来说,选择是根据你的具体需求和代码设计来决定的。如果你不确定,可以根据实际情况进行测试和性能分析,以选择最适合的方式。

英文:

Are maps passed by value or reference in Go ?

It is always possible to define a function as following, but is this an overkill ?

func foo(dat *map[string]interface{}) {...}

Same question for return value. Should I return a pointer to the map, or return the map as value ?

The intention is of course to avoid unnecessary data copy.

答案1

得分: 143

在这个线程中,你会找到你的答案:

https://stackoverflow.com/questions/28384343/golang-accessing-a-map-using-its-reference

> 你不需要在 map 中使用指针。
>
> Map 类型是引用类型,就像指针或切片一样1
>
> 如果你需要改变 Session,你可以使用指针:
>
> map[string]*Session
>
> https://blog.golang.org/go-maps-in-action

英文:

In this thread you will find your answer :

https://stackoverflow.com/questions/28384343/golang-accessing-a-map-using-its-reference

> You don't need to use a pointer with a map.
>
> Map types are reference types, like pointers or slices1
>
> If you needed to change the Session you could use a pointer:
>
> map[string]*Session
>
> https://blog.golang.org/go-maps-in-action

答案2

得分: 51

以下是Dave Cheney在《如果地图不是引用变量,那它是什么?》一文中的一些部分:

地图值是指向runtime.hmap结构的指针。

和结论:

结论

地图和通道一样,但与切片不同,它们只是指向运行时类型的指针。如上所示,地图只是指向runtime.hmap结构的指针。

地图在Go程序中具有与任何其他指针值相同的指针语义。除了编译器将地图语法重写为对runtime/hmap.go中的函数的调用之外,没有任何魔法。

关于map语法的历史/解释的有趣部分:

如果地图是指针,它们不应该是*map[key]value吗?

这是一个很好的问题,如果地图是指针值,为什么表达式make(map[int]int)返回类型为map[int]int的值。它不应该返回*map[int]int吗?Ian Taylor最近在golang-nuts的线程中回答了这个问题1

在早期,我们现在称为地图的东西被写成指针,所以你写*map[int]int。当我们意识到没有人写map而不写*map时,我们就摒弃了这种写法。

可以说,将类型从*map[int]int重命名为map[int]int,虽然令人困惑,因为该类型看起来不像指针,但比一个无法解引用的指针形状的值更不令人困惑。

英文:

Here are some parts from If a map isn’t a reference variable, what is it? by Dave Cheney:

> A map value is a pointer to a runtime.hmap structure.

and conclusion:

> Conclusion
>
> Maps, like channels, but unlike slices, are just pointers to runtime
> types. As you saw above, a map is just a pointer to a runtime.hmap
> structure.
>
> Maps have the same pointer semantics as any other pointer value in a
> Go program. There is no magic save the rewriting of map syntax by the
> compiler into calls to functions in runtime/hmap.go.

And an interesting bit about history/explanation of map syntax:

> If maps are pointers, shouldn’t they be *map[key]value?
>
> It’s a good question that if maps are pointer values, why does the
> expression make(map[int]int) return a value with the type
> map[int]int. Shouldn’t it return a *map[int]int? Ian Taylor
> answered this recently in a golang-nuts thread<sup>1</sup>.
>
> > In the very early days what we call maps now were written as pointers,
> > so you wrote *map[int]int. We moved away from that when we realized
> > that no one ever wrote map without writing *map.
>
>
> Arguably renaming the type from *map[int]int to map[int]int, while
> confusing because the type does not look like a pointer, was less
> confusing than a pointer shaped value which cannot be dereferenced.

答案3

得分: 16

不。默认情况下,地图是引用类型。

package main

import "fmt"

func mapToAnotherFunction(m map[string]int) {
    m["hello"] = 3
    m["world"] = 4
    m["new_word"] = 5
}

// func mapToAnotherFunctionAsRef(m *map[string]int) {
// m["hello"] = 30
// m["world"] = 40
// m["2ndFunction"] = 5
// }

func main() {
    m := make(map[string]int)
    m["hello"] = 1
    m["world"] = 2

    // 初始状态
    for key, val := range m {
        fmt.Println(key, "=>", val)
    }

    fmt.Println("-----------------------")

    mapToAnotherFunction(m)
    // 传递给函数作为指针后
    for key, val := range m {
        fmt.Println(key, "=>", val)
    }

    // 尝试取消注释此行
    fmt.Println("-----------------------")

    // mapToAnotherFunctionAsRef(&m)
    // // 传递给函数作为指针后
    // for key, val := range m {
    //     fmt.Println(key, "=>", val)
    // }

    // 输出
    // hello => 1
    // world => 2
    // -----------------------
    // hello => 3
    // world => 4
    // new_word => 5
    // -----------------------

}

来自Golang博客-

> 地图类型是引用类型就像指针或切片一样因此上面的m的值为nil它没有指向初始化的地图当读取时nil地图的行为类似于空地图但尝试写入nil地图将导致运行时恐慌不要这样做要初始化地图请使用内置的make函数

```go
// make函数示例
m = make(map[string]int)

代码片段链接 玩一下。

英文:

No. Maps are reference by default.

	package main
import &quot;fmt&quot;
func mapToAnotherFunction(m map[string]int) {
m[&quot;hello&quot;] = 3
m[&quot;world&quot;] = 4
m[&quot;new_word&quot;] = 5
}
// func mapToAnotherFunctionAsRef(m *map[string]int) {
// m[&quot;hello&quot;] = 30
// m[&quot;world&quot;] = 40
// m[&quot;2ndFunction&quot;] = 5
// }
func main() {
m := make(map[string]int)
m[&quot;hello&quot;] = 1
m[&quot;world&quot;] = 2
// Initial State
for key, val := range m {
fmt.Println(key, &quot;=&gt;&quot;, val)
}
fmt.Println(&quot;-----------------------&quot;)
mapToAnotherFunction(m)
// After Passing to the function as a pointer
for key, val := range m {
fmt.Println(key, &quot;=&gt;&quot;, val)
}
// Try Un Commenting This Line
fmt.Println(&quot;-----------------------&quot;)
// mapToAnotherFunctionAsRef(&amp;m)
// // After Passing to the function as a pointer
// for key, val := range m {
//	fmt.Println(key, &quot;=&gt;&quot;, val)
// }
// Outputs
// hello =&gt; 1
// world =&gt; 2
// -----------------------
// hello =&gt; 3
// world =&gt; 4
// new_word =&gt; 5
// -----------------------
}

From Golang Blog-

>Map types are reference types, like pointers or slices, and so the value of m above is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function:

// Ex of make function
m = make(map[string]int)

Code Snippet Link Play with it.

huangapple
  • 本文由 发表于 2016年11月18日 23:42:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/40680981.html
匿名

发表评论

匿名网友

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

确定