Golang对象作用域与循环和线程

时间:2018-08-04 19:56:49

标签: go

很明显,我对范围界定不了解。我已将问题简化为以下(run it at 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()更改该值。

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

1 个答案:

答案 0 :(得分:2)

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


代码

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,当赋值/作为参数传递/从函数返回时,它始终会复制。
    您可以通过以下两种方法来征服:
    • 改为使用指针。
      在这种情况下,该结构只有一个副本。
    • 让结构中的字段成为指针或类似的引用类型(例如slice或map)
      在这种情况下,该结构有2个副本,但是这些字段引用的是相同的基础数据结构。
      但是在您的代码中,bool不是引用类型,因此不能使用它。
  • 类似于structarray的行为。
    尽管在大多数情况下,您只会使用slice
  • 另一方面,slice / map包含对保存实际数据的基础数据结构的引用。
    因此,如果您将一个slice分配给另一个slice变量,或者从一个函数返回它,则将有2个slice,但是它们仍然引用相同的基础数据结构(一个array
    因此,对一个切片所做的更改将对其他切片可见。

顺便说一句,Effective go是了解go的这些棘手细节的好地方:)