[英]Why is this map empty when I populate it in a Goroutine?
type driver struct {
variables map[string]string
}
var Drivers []driver
func main() {
driver := driver{
variables: make(map[string]string),
}
Drivers = append(Drivers, driver)
driver.variables = make(map[string]string) // Commenting this line makes it work, too
done := make(chan bool)
go driver.populate(done)
<-done
fmt.Print(Drivers[0].variables)
}
func (this *driver) populate(done chan bool) {
time.Sleep(500 * time.Millisecond)
this.variables["a"] = "b"
done <- true
}
我期望:
map[a:b]
實際結果:
map[]
問題很簡單:你有一片driver
:
var Drivers []driver
請注意, Drivers
是一些結構類型的片段,而不是指針的一部分!
附加內容時(或者為其中一個元素賦值):
Drivers = append(Drivers, driver)
這會附加(或分配)值的副本! 所以當你以后這樣做時:
driver.variables = make(map[string]string)
它將為driver.variables
設置一個新的map值,但這與存儲在Drivers
的值不同(更准確地說是在Drivers[0]
)。
稍后您將填充driver.variables
,但您打印Drivers[0].variables
。 它們是2個不同的結構值,具有2個不同的地圖值。 Goroutines在這里沒有發揮作用(他們正確地同步,所以他們不應該這樣做)。
你會打印driver.variables
:
fmt.Print(driver.variables)
你會看到(在Go Playground上試試):
map[a:b]
如果你注釋掉這一行:
driver.variables = make(map[string]string) // Commenting this line makes it work, too
它可以工作, 但只是因為即使你有2個struct值,它們也有相同的map值(相同的map頭指向同一個map數據結構)。
如果在結構值Drivers[0]
上調用driver.populate()
(並且堅持打印Drivers[0].variables
),也可以使它工作:
go Drivers[0].populate(done)
// ...
fmt.Print(Drivers[0].variables)
在Go Playground嘗試這個。
如果Drivers
是一個指針,你也可以使它工作:
var Drivers []*driver
// ...
driver := &driver{
variables: make(map[string]string),
}
因為driver
和Driver[0]
將是相同的指針(因為初始映射不再可訪問,所以只有一個struct值和一個map值)。 在Go Playground嘗試這個。
使用goroutine版本你沒有獲得未初始化的映射的原因是當main函數返回時,程序退出: 它不等待其他(非主要)goroutine完成 。 請注意主要功能本身是goroutine。
因此,即使您使用以下內容初始化地圖:
driver.variables = make(map[string]string)
它並不意味着您實際填充值,您只是初始化哈希映射數據結構並返回指向它的映射值。
地圖類型是引用類型,如指針或切片,因此上面的m值為nil; 它沒有指向初始化的地圖。 在讀取時,nil映射的行為類似於空映射,但嘗試寫入nil映射將導致運行時出現混亂。 不要那樣做。 要初始化地圖,請使用內置的make函數。
如果您首先刪除go
關鍵字,它將初始化driver.variables
地圖。 但是因為它在同一個線程(主線程)中運行,並且你首先在populate
函數上放置一個時間延遲,它將初始化地圖,然后填充它。
我最好使用頻道而不是sleep
s:
package main
import (
"fmt"
"time"
)
type driver struct {
variables map[string]string
}
var Drivers []driver
func main() {
driver := driver{
variables: make(map[string]string),
}
Drivers = append(Drivers, driver)
done := make(chan bool)
go driver.populate(done)
<-done // wait for goroutine to complete
fmt.Print(Drivers[0].variables)
}
func (this *driver) populate(done chan bool) {
time.Sleep(500 * time.Millisecond)
this.variables["a"] = "b"
done <- true
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.