首页 > 解决方案 > 带有循环和线程的 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()在循环运行时更改该值。

将布尔值移动到全局变量会给出我想要的行为(从循环的角度来看,值已更改),但我需要布尔值成为对象的一部分,因为该对象会有多个实例化。

标签: go

解决方案


我稍微修改了您的代码,现在它可以按您的预期工作。


代码

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不是引用类型,所以不能使用它。
  • 类似structarray行为类似。
    尽管大多数时候,您只会使用它slice
  • 另一方面,slice/map包含对保存实际数据的底层数据结构的引用。
    因此,如果您将切片分配给另一个切片变量,或者从函数中返回它,将会有 2 slice,但它们仍然引用相同的底层数据结构(an array)
    因此,对一个切片所做的更改将对另一个切片可见。

顺便说一句,有效的围棋是了解围棋这些棘手细节的好地方 :)


推荐阅读