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[]
答案 0 :(得分:4)
问题很简单:你有一片driver
s:
var Drivers []driver
请注意,Drivers
是一些结构类型的切片,而不是指针的一部分!
当您附加某些内容(或者为其中一个元素指定值)时:
Drivers = append(Drivers, driver)
这会附加(或分配)值的副本!所以当你稍后这样做时:
driver.variables = make(map[string]string)
它会将新地图值设置为driver.variables
,但这与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个结构值,它们也具有相同的地图值(相同的地图标题指向相同的地图数据结构)。
如果您在结构值driver.populate()
上调用Drivers[0]
(并坚持打印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]
将是相同的指针(因为初始地图不再可访问,所以只有一个结构值和一个地图值)。请在Go Playground上尝试此操作。
答案 1 :(得分:0)
使用goroutine版本你没有得到未初始化的地图的原因是当主函数返回时,程序退出:它不等待其他(非主要)goroutines完成 。请注意,主要功能本身就是goroutine。
所以即使你使用:
初始化地图driver.variables = make(map[string]string)
这并不意味着您实际填充了值,您只是初始化哈希映射数据结构并返回指向它的映射值。
地图类型是引用类型,如指针或切片,等等 m以上的值为零;它没有指向初始化的地图。没有 在阅读时,map的行为类似于空地图,但尝试写入 零映射会导致运行时恐慌;不要那样做。初始化一个 map,使用内置的make函数。
如果您先删除go
关键字,则会初始化driver.variables
地图。但是因为它在同一个线程(主线程)中运行,并且你首先在populate
函数上放置了一个时间延迟,它会初始化地图,然后填充它。
答案 2 :(得分:0)
我最好使用频道代替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
}