带通道的 Golang 内存参考

Golang memory reference with Channels

当我尝试运行这段代码时,结果是。

{Yellow 99}
{Yellow 10}

重发link

package main

import (
  "fmt"
  "sync"
)

type Fruit struct {
  color string
  price int
}

func (f *Fruit) UpdatePrice(newPrice int) {
  f.price = newPrice
}

func main() {
  mango := Fruit{color: "Yellow", price: 10}
  var wg sync.WaitGroup
  one := make(chan Fruit)
  wg.Add(1)
  go func() {
    defer wg.Done()
    freshMango := <- one
    freshMango.UpdatePrice(99)
    fmt.Println(freshMango)
  }()
  one <- mango
  wg.Wait()
  fmt.Println(mango)
}

由于我更新了水果的价格,我希望这也能反映在芒果的最终印刷品中,但两者的价值不同。谁能详细说明这种情况下发生了什么?

您目前正在将 Fruit 对象的副本传递到您的 "one" 频道。您需要将指向该对象的指针传递给您的频道,并允许频道支持 *Fruit 而不是 Fruit。

package main

import (
  "fmt"
  "sync"
)

type Fruit struct {
  color string
  price int
}

func (f *Fruit) UpdatePrice(newPrice int) {
  f.price = newPrice
}

func main() {
  mango := Fruit{color: "Yellow", price: 10}
  var wg sync.WaitGroup
  one := make(chan *Fruit)
  wg.Add(1)
  go func() {
    defer wg.Done()
    var freshMango *Fruit
    freshMango = <- one
    freshMango.UpdatePrice(99)
    fmt.Println(*freshMango)
  }()
  one <- &mango
  wg.Wait()
  fmt.Println(mango)
}
package main

import (
  "fmt"
  "sync"
)

type Fruit struct {
  color string
  price int
}

func (f *Fruit) UpdatePrice(newPrice int) {
  f.price = newPrice
}

func main() {
  // instead of pushing a copy of a Fruit struct you need to push a pointer of Fruit into the channel
  mango := &Fruit{color: "Yellow", price: 10}
  var wg sync.WaitGroup
  one := make(chan *Fruit)
  wg.Add(1)
  go func() {
    defer wg.Done()
    freshMango := <- one
    freshMango.UpdatePrice(99)
    fmt.Println(freshMango)
  }()
  one <- mango
  wg.Wait()
  fmt.Println(mango)
}

Golang 在将每个 none 指针值传递给函数、通道等之前复制它

将指针从一个 goroutine 传递到另一个 goroutine 不是好的做法。它会产生非常讨厌的错误,因为两个 goroutines 都可以操纵底层类型。

任何有权访问此指针的 goroutine 都可以操作底层类型,并且没有强制执行应如何操作此类型的命令。

在本地机器上编译这个程序

    package main

import (
    "fmt"
    "sync"
)

func main() {

    i := new(int)
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        *i += 10
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        *i *= 10
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        *i = *i / 10
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        *i += 10
        wg.Done()
    }()

    wg.Add(1)
    go func() {
        *i += 10
        wg.Done()
    }()
    wg.Wait()

    fmt.Println(*i)
}

现在运行这个go程序连续1000次

for i in {1..1000}; do ./main; done

如果你运行这个程序那么你会看到结果将是"randomly"。