在 golang 中的包之间传递映射

在golang中,我知道map函数之间是以引用的形式传递的,但是今天遇到了一个奇怪的情况。代码的运行结果不是我想象的那样。我将其简化为以下代码行。


.

├── go.mod

├── main.go

├── packageA

│   └── a.go

└── packageB

    └── b.go


main.go 文件


package main


import (

    "gostudy/packageA"

    "gostudy/packageB"

)


func main() {

    packageB.UseMap(packageA.M, packageA.InitMap)

}


package packageA


var M map[string]string


func InitMap() {

    M = make(map[string]string)

    M["hello"] = "go"

}

b.go


package packageB


import "fmt"


func UseMap(m map[string]string, callback func()) {

    callback()

    fmt.Println(m)

}

可以看到,a.go文件中只有一个全局声明的变量。我以为上面的程序应该输出map[hello:go],但它实际上输出了一个空的map[]。我对此很困惑,希望得到答案。


弑天下
浏览 115回答 2
2回答

收到一只叮咚

在调用函数以将其替换为地图的新版本之前,您将地图的旧值作为参数传递。假设packageA.M包含值map[string]string{"foo": "bar"}。该main()函数读取变量并获取对该映射的引用,并将它和函数传递给packageB.UseMap().在 内部packageB.UseMap(),您的代码packageA.InitMap()通过回调进行调用。这不会修改现有地图;相反,它会创建一个新地图,将其分配给全局变量并填充它。任何拥有旧地图副本的东西都不会受到影响,并且您显示的代码不会重新读取packageA.M.我建议完全放弃全局变量:它会使代码难以测试,并且一旦开始使用 goroutines 就会出现潜在问题。只需让您的设置函数返回新地图即可。package packageAfunc InitMap() map[string]string {        return map[string]string{"hello": "go"}}package packageBfunc UseMap(callback func() map[string]string) {        m := callback()        fmt.Println(m)}package mainimport "packageA"import "packageB"func main() {        packageB.UseMap(packageA.InitMap)}

喵喵时光机

就像已接受的答案的旁注一样,如果您看一下:// ...import (    "reflect"    "fmt")// ... other functions// I defined all of the functions in a single paackage, so I can access them both herefunc UseMap(m map[string]string, callback func()) {    fmt.Println(reflect.ValueOf(m).Pointer() == reflect.ValueOf(M).Pointer()) // prints true, they have the same reference    callback()     // inside callback, M global variable takes a whole new reference    // when "M = make(...)"    // and then =>     fmt.Println(reflect.ValueOf(m).Pointer() == reflect.ValueOf(M).Pointer()) // prints false}如果你想在不改变你的 api 的情况下避免这种情况,你可以在你的包 A 中这样做:package packageAvar M map[string]string = make(map[string]string)func InitMap() {    M["hello"] = "go"}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go