迭代golang无缓冲通道时的输出令人困惑

问题描述 投票:0回答:2

当迭代golang无缓冲通道时,我遇到一个令人困惑的输出。通道定义为chan []int。然后,我将两个片段推到通道[0 1]和[2 3]。但是,当我从通道中获取元素时,得到了[2 3]和[2 3]。为什么会这样?

package main

import "fmt"
import "sync"

func producer(jobs chan []int, wg *sync.WaitGroup) {
    defer wg.Done()

    a := make([]int, 2)
    index := 0
    for i := 0; i < 4; i++ {
        a[index] = i
        index++
        if index == 2 {
            index = 0
            fmt.Printf("a: %+v\n", a)
            jobs <- a
        }    
    }

    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan []int, 2)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

预期输出:

a: [0 1]
a: [2 3]
job: [0 1]
job: [2 3]

实际输出:

a: [0 1]
a: [2 3]
job: [2 3]
job: [2 3]
go slice channel
2个回答
2
投票

切片包含指向支持数组的指针。通过通道发送切片时,您正在发送对该后备阵列的引用,因此即使在接收端多次读取该切片时,您实际上也引用了同一共享后备阵列。

您可以为每次迭代创建一个新的切片并将其发送。每个切片将具有一个单独的支持阵列,并且将按预期工作。


0
投票

略微修改了程序以更好地阅读。

package main

import "fmt"
import "sync"

func producer(jobs chan []int, wg *sync.WaitGroup) {
    defer wg.Done()

    a := make([]int, 2)
    a[0] = 1
    a[1] = 2
            jobs <- a   //We are passing memory location of slice ( is nature of slice ), so the values changing next line will affect here too
    a[0] = 2
    a[1] = 3
           jobs <- a  


    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan []int, 2)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

我尝试过使用Array的同一程序,然后我们将得到您期望的结果,请参见下面的代码

package main

import "fmt"
import "sync"

func producer(jobs chan [2]int, wg *sync.WaitGroup) {
    defer wg.Done()

   var a[2]int
    a[0] = 1
    a[1] = 2
            jobs <- a   
    a[0] = 2
    a[1] = 3
           jobs <- a  


    close(jobs)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    jobs := make(chan [2]int)
    go producer(jobs, &wg)
    for job := range jobs {
        fmt.Printf("job: %+v\n", job)
    }

    wg.Wait()
}

Playground Link - Program using Slice

Playground Link - Program using Array

基本规则是切片通过引用传递

© www.soinside.com 2019 - 2024. All rights reserved.