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

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

關于映射、字符串指針和閉包的問題

關于映射、字符串指針和閉包的問題

Go
藍山帝景 2022-06-13 15:03:41
當我嘗試轉換為時,我發現我的代碼存在錯誤(我map[string]string正在map[string]*string使用的 API 需要轉換)。問題在我的第一個方法中,我嘗試遍歷源映射中的每個條目,aMap并將每個條目的字符串值轉換為字符串指針,并將此指針值分配給目標映射,bMap與aMap. 我最初預計保留的取消引用值bMap與aMap同一鍵下的值相同。但是,事實證明,在同一鍵下, 的延遲值bMap不共享相同的值。aMap我的問題是:為什么會出現這個問題?我能夠使用第二種方法解決該問題,首先定義一個接收字符串并返回指針的函數,這樣我就能夠正確返回延遲值以共享與aMap同一鍵下相同的值。為什么這種方法有效?另外,只是好奇,為什么&(*v)Go 中有語法錯誤?我還嘗試聲明一個虛擬變量val := *v,并將其分配給bMapusingbMap[key] = &val但無濟于事。錯誤說invalid indirect of v (type string)源代碼https://play.golang.org/p/ZG7XS2vJx0yfunc main() {    aMap := make(map[string]string)    aMap["foo"] = "bar"    aMap["bar"] = "baz"    aMap["baz"] = "foo"    bMap := make(map[string]*string)    for k, v := range(aMap){        bMap[k] = &v    }    // first method    fmt.Println("1st method, map[string]*string, bMap")     for k, v := range(bMap){        fmt.Printf("bMap[%s] = %s / %s, aMap[%s] = %s\n",        k, *bMap[k], *v, k, aMap[k])    }    pString := func(v string) *string{ return &v }    for k, v := range(aMap){        bMap[k] = pString(v)    }    // second method    fmt.Println("2nd method, map[string]*string, bMap")    for k, v := range(bMap){        fmt.Printf("bMap[%s] = %s / %s, aMap[%s] = %s\n",        k, *bMap[k], *v, k, aMap[k])    }    // expected results    fmt.Println("Expected result: map[string]string, cMap")    cMap := make(map[string]string)    for k, v := range(aMap){        cMap[k] = v    }    for k, v := range(cMap){        fmt.Printf("cMap[%s] = %s / %s, aMap[%s] = %s\n",        k, cMap[k], v, k, aMap[k])    }}輸出1st method, map[string]*string, bMapbMap[baz] = foo / foo, aMap[baz] = foobMap[foo] = foo / foo, aMap[foo] = barbMap[bar] = foo / foo, aMap[bar] = baz2nd method, map[string]*string, bMapbMap[baz] = foo / foo, aMap[baz] = foobMap[foo] = bar / bar, aMap[foo] = barbMap[bar] = baz / baz, aMap[bar] = bazExpected result: map[string]string, cMapcMap[baz] = foo / foo, aMap[baz] = foocMap[foo] = bar / bar, aMap[foo] = barcMap[bar] = baz / baz, aMap[bar] = baz太感謝了。
查看完整描述

2 回答

?
牧羊人nacy

TA貢獻1862條經驗 獲得超7個贊

方法 1 中的問題是您沒有獲取字符串的地址,而是獲取了它所在變量的地址。在 Go 中,&v返回變量的地址v。當你有這樣的循環時:


for k, v := range aMap {

    ...

}

您在循環開始時聲明的變量k和v在整個循環中使用的變量是相同的。它們只是在每次迭代中被分配了不同的值。在該循環中,&v總是計算出相同的值: 的地址v。這就是為什么您的所有地圖條目都出現在"foo":"foo"中的最后一個值v,并且它仍然存在。


您可以通過更改字符串值來查看此行為。所有的地圖鍵都會改變:


*bMap["foo"] = "quux"

fmt.Println(*bMap["bar"]) // prints "quux"

方法 2 有效,因為函數的每次調用都有自己的局部變量。Go 保證,如果您從函數返回局部變量的地址,該變量將被分配在堆上,只要需要它就可以使用它。所以你的輔助函數告訴 Go 分配一個新string變量,將傳入的字符串復制到它,然后返回它的地址。


這是另一種可行的方法:


dMap := make(map[string]*string)

for k, v := range(aMap){

    dMap[k] = new(string)

    *dMap[k] = v

}

這會分配一個新的字符串變量,將其地址保存在映射中,然后將 v 復制到其中。如果您要經常這樣做,輔助函數可能是最好的。


您嘗試的代碼如下:


v := "foo"

val := *v

bMap[key] = &val

不起作用,因為您說“v 是一個字符串;現在將字符串指向的值存儲在 val 中”,但該字符串不是指針。


查看完整回答
反對 回復 2022-06-13
?
嗶嗶one

TA貢獻1854條經驗 獲得超8個贊

問題中的第一種方法使用v所有鍵的單個循環變量的地址。您看到的值是最后一個設置為 的值v。


通過為每次迭代聲明一個新變量并獲取該變量的地址來修復。


bMap := make(map[string]*string)

for k, v := range aMap {

    v := v // declare new variable v initialized with value from outer v

    bMap[k] = &v

}

問題中的第二種方法還為循環中的每次迭代聲明了一個新變量。新變量是函數參數。


這個答案顯示了解決這個問題的慣用方法。請參閱Go 常見問題解答:作為 goroutine 運行的閉包會發生什么?在閉包和 goroutine 的上下文中討論相同的問題。


查看完整回答
反對 回復 2022-06-13
  • 2 回答
  • 0 關注
  • 159 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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