亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 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條經驗 獲得超5個贊

在調用函數以將其替換為地圖的新版本之前,您將地圖的舊值作為參數傳遞。


假設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 關注
  • 134 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號