【问题标题】:How to make struct survive outside its Go routine when using pointers to external struct使用指向外部结构的指针时如何使结构在其 Go 例程之外生存
【发布时间】:2019-10-18 14:00:20
【问题描述】:

当我使用go run main.go 运行此代码时,我会看到以下输出:

inner: {Bar:{Baz:xyz} BarPtr:0xc0000101e0}
outer: {Bar:{Baz:} BarPtr:<nil>}

我不明白为什么在将指针传递给例程时,在该例程中创建的结构 不能通过指针暴露在外部。

我知道我可以使用通道来发布在 Go 例程中创建的结构,但是我正在处理的这段代码需要太多额外的样板代码。如果可能,我想使用带有指针的等待组,但我找不到方法,所以我想知道这是否可能?

对我来说,我应该能够通过指针公开一个内部结构,但我不确定编译器是否会默默地忽略这一点,或者我无法理解 Go 的一些基本特性?

package main

import (
    "fmt"
    "sync"
)

type Foo struct {
    Bar    Bar
    BarPtr *Bar
}

type Bar struct {
    Baz string
}

func main() {
    foo := Foo{}
    var wg sync.WaitGroup
    // the real example has more routines, so I need a wait group
    wg.Add(1)
    go func(strct *Foo) {
        defer wg.Done()
        bar1 := Bar{
            Baz: "xyz",
        }
        bar2 := Bar{
            Baz: "abc",
        }
        ownFoo := Foo{
            Bar:    bar1,
            BarPtr: &bar2,
        }
        fmt.Printf("inner: %+v\n", ownFoo)
        strct = &ownFoo
    }(&foo)
    wg.Wait()
    fmt.Printf("outer: %+v\n", foo)
}

【问题讨论】:

  • struct 是一个最初指向 foo 的指针。让这个指针指向其他地方(这里指向 ownFoo)丝毫不会影响 foo,我不清楚为什么会期望它会这样做。
  • 看来我可以使用带有等待组的全局变量,所以我知道 Go 例程是使用该全局变量完成的,我可以安全地访问它的值,或者我可以使用通道。我想使用指针来避免使用从 Go 例程内部引用的全局变量。
  • 即使您尝试执行的指针操作会起作用,您仍然需要围绕指针分配进行同步。代码中的注释表明无论如何都需要一个WaitGroup,那为什么不直接修改foo呢?
  • foo 可以从不同的包创建和注入。我试图尽量减少样板代码的数量(例如,不需要额外的“包装”结构和通道),但通过使用等待组和避免全局变量来保持某种安全/同步。
  • @TPPZ goroutine 与否,以更改您使用*strct = ownFoo 而不是strct = &amp;ownFoo 的指针指向的值。 strct = &amp;ownFoo 改变的是指针,而不是指向的值。

标签: pointers go struct goroutine


【解决方案1】:

通过指针strct设置foo值的正确表达式是:

*strct = ownFoo

另一方面,表达式

strct = &ownFoo

strct 指针设置为ownFoo 的地址,并保持foo 值不变。


请记住,如果您有一个从多个 goroutine 访问的变量,并且其中至少有一个正在编写/修改该变量,那么如果没有适当的同步,您的代码必然会遇到数据竞争,无论是否变量可以直接访问,也可以通过本地指针访问。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多