为了账号安全,请及时绑定邮箱和手机立即绑定

在 golang 中的包之间传递映射

在 golang 中的包之间传递映射

Go
弑天下 2023-01-03 17:07:18
在golang中,我知道map函数之间是以引用的形式传递的,但是今天遇到了一个奇怪的情况。代码的运行结果不是我想象的那样。我将其简化为以下代码行。.├── go.mod├── main.go├── packageA│   └── a.go└── packageB    └── b.gomain.go 文件package mainimport (    "gostudy/packageA"    "gostudy/packageB")func main() {    packageB.UseMap(packageA.M, packageA.InitMap)}前package packageAvar M map[string]stringfunc InitMap() {    M = make(map[string]string)    M["hello"] = "go"}b.gopackage packageBimport "fmt"func UseMap(m map[string]string, callback func()) {    callback()    fmt.Println(m)}可以看到,a.go文件中只有一个全局声明的变量。我以为上面的程序应该输出map[hello:go],但它实际上输出了一个空的map[]。我对此很困惑,希望得到答案。
查看完整描述

2 回答

?
收到一只叮咚

TA贡献1821条经验 获得超4个赞

在调用函数以将其替换为地图的新版本之前,您将地图的旧值作为参数传递。


假设packageA.M包含值map[string]string{"foo": "bar"}。该main()函数读取变量并获取对该映射的引用,并将它和函数传递给packageB.UseMap().


在 内部packageB.UseMap(),您的代码packageA.InitMap()通过回调进行调用。这不会修改现有地图;相反,它会创建一个新地图,将其分配给全局变量并填充它。任何拥有旧地图副本的东西都不会受到影响,并且您显示的代码不会重新读取packageA.M.


我建议完全放弃全局变量:它会使代码难以测试,并且一旦开始使用 goroutines 就会出现潜在问题。只需让您的设置函数返回新地图即可。


package packageA


func InitMap() map[string]string {

        return map[string]string{"hello": "go"}

}

package packageB


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

        m := callback()

        fmt.Println(m)

}

package main


import "packageA"

import "packageB"


func main() {

        packageB.UseMap(packageA.InitMap)

}


查看完整回答
反对 回复 2023-01-03
?
喵喵时光机

TA贡献1846条经验 获得超7个赞

就像已接受的答案的旁注一样,如果您看一下:



// ...

import (

    "reflect"

    "fmt"

)


// ... other functions

// I defined all of the functions in a single paackage, so I can access them both here

func 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 packageA


var M map[string]string = make(map[string]string)


func InitMap() {

    M["hello"] = "go"

}


查看完整回答
反对 回复 2023-01-03
  • 2 回答
  • 0 关注
  • 114 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号