当我在 Goroutine 中填充它时,为什么这张地图是空的?
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[]
使用goroutine版本没有得到未初始化映射的原因是当main函数returns,程序退出:它不等待其他(非main) ) goroutines 完成。请注意 main 函数本身是一个 goroutine。
因此,即使您使用以下方式初始化地图:
driver.variables = make(map[string]string)
这并不意味着您实际填充了值,您只是初始化了一个哈希映射数据结构和 returns 指向它的映射值。
Map types are reference types, like pointers or slices, and so the
value of m above is nil; it doesn't point to an initialized map. A nil
map behaves like an empty map when reading, but attempts to write to a
nil map will cause a runtime panic; don't do that. To initialize a
map, use the built in make function.
如果您先删除 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
}
问题很简单:你有一片 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 个结构值,它们具有相同的映射值(相同的映射 header 指向相同的映射数据结构)。
如果你在结构值 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]
将是同一个指针(您将只有一个结构值和一个映射值,因为初始映射不再可访问)。在 Go Playground.
上试试这个
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[]
使用goroutine版本没有得到未初始化映射的原因是当main函数returns,程序退出:它不等待其他(非main) ) goroutines 完成。请注意 main 函数本身是一个 goroutine。
因此,即使您使用以下方式初始化地图:
driver.variables = make(map[string]string)
这并不意味着您实际填充了值,您只是初始化了一个哈希映射数据结构和 returns 指向它的映射值。
Map types are reference types, like pointers or slices, and so the value of m above is nil; it doesn't point to an initialized map. A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function.
如果您先删除 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
}
问题很简单:你有一片 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 个结构值,它们具有相同的映射值(相同的映射 header 指向相同的映射数据结构)。
如果你在结构值 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]
将是同一个指针(您将只有一个结构值和一个映射值,因为初始映射不再可访问)。在 Go Playground.