go - 带有循环和线程的 Golang 对象范围
问题描述
很明显,我对范围界定一无所知。我已将问题提炼为以下内容(在 The Go Playground 运行):
package main
import (
"log"
"time"
)
type mystruct struct {
mybool bool
}
func new() mystruct {
var ms mystruct
go func() {
for {
time.Sleep(time.Second/2)
log.Println("loop says:",ms.mybool)
}
}()
return ms
}
func (m *mystruct) switchIt() {
if m.mybool {
m.mybool = false
} else {
m.mybool = true
}
}
func main() {
thing := new()
time.Sleep(2 * time.Second)
thing.switchIt()
time.Sleep(2 * time.Second)
thing.switchIt()
time.Sleep(2 * time.Second)
thing.switchIt()
}
就像现在一样,布尔值始终是从匿名函数false
中无限循环的角度来看的。new()
我试图switchIt()
在循环运行时更改该值。
将布尔值移动到全局变量会给出我想要的行为(从循环的角度来看,值已更改),但我需要布尔值成为对象的一部分,因为该对象会有多个实例化。
解决方案
我稍微修改了您的代码,现在它可以按您的预期工作。
代码
package main
import (
"log"
"time"
)
type mystruct struct {
mybool bool
}
func newThing() *mystruct {
var ms mystruct
go func() {
for {
time.Sleep(time.Second / 2)
log.Println("loop says:", ms.mybool)
}
}()
return &ms
}
func (m *mystruct) switchIt() {
if m.mybool {
m.mybool = false
} else {
m.mybool = true
}
}
func main() {
thing := newThing()
time.Sleep(2 * time.Second)
thing.switchIt()
time.Sleep(2 * time.Second)
thing.switchIt()
time.Sleep(2 * time.Second)
thing.switchIt()
}
提示
您的代码问题:
- 我将您的更改
new()
为newThing()
,因为它与内置new()
功能混淆。
即使你可以这样写,但它很容易出错。 - 您的原始
new()
返回结构的副本,因此在调用之后new()
,结构有 2 个副本,这就是您永远无法更改它的原因。
在这种情况下,最好改为返回一个指针。
提示go
:
- 对于
struct
,当分配/作为参数传递/从函数返回时,它总是制作一个副本。
你有 2 种选择来克服这个问题:- 请改用指针。
在这种情况下,结构只有一个副本。 - 让结构中的字段为指针或类似的引用类型(例如切片或映射)。
在这种情况下,该结构有 2 个副本,但这些字段引用相同的底层数据结构。
但是在你的代码中,bool
不是引用类型,所以不能使用它。
- 请改用指针。
- 类似
struct
,array
行为类似。
尽管大多数时候,您只会使用它slice
。 - 另一方面,
slice
/map
包含对保存实际数据的底层数据结构的引用。
因此,如果您将切片分配给另一个切片变量,或者从函数中返回它,将会有 2slice
,但它们仍然引用相同的底层数据结构(anarray
)。
因此,对一个切片所做的更改将对另一个切片可见。
顺便说一句,有效的围棋是了解围棋这些棘手细节的好地方 :)
推荐阅读
- docker - 如何根据 Jenkins 声明性管道中的参数使用不同的私有 docker 代理?
- python - 将自定义变量/统计信息添加到 tqdm 条
- mysql - 分别在多列中查找最小值
- csv - JMeter 抛出“文件从不保留”错误
- metal - 如何通过 Metal 再次提交相同的命令?
- asp.net-mvc - 添加子实体在本地有效,但在实时 Azure 站点上无效
- azure-devops - 以编程方式访问 Azure Devops 中的管道变量组
- sql - SQL Select:匹配id的行是否都具有相同的列值
- testing - 对哪种类型的测试感到困惑——理智、烟雾或回归
- java - 主线程在 CompletableFuture 完成之前退出