2

我想创建切片并添加从通道返回的值。以下是我尝试但无法解决的代码。

我必须发送切片的地址,但我无法弄清楚如何:(

package main

import "fmt"
import "time"

func sendvalues(cs chan int){
    for i:=0;i<10;i++{
        cs<-i   
    }   
}

func appendInt(cs chan int, aINt []int)[]*int{
    for {
        select {
        case i := <-cs:
            aINt = append(aINt,i)//append returns new type right ?
            fmt.Println("slice",aINt)
        }   
    }   
}



func main() {
    cs := make(chan int)
    intSlice := make([]int, 0,10)

    fmt.Println("Before",intSlice)
    go sendvalues(cs)
    go appendInt(cs,intSlice)// I have to pass address here

    time.Sleep(999*999999)
    fmt.Println("After",intSlice)
}
4

1 回答 1

13

您的代码无法工作有两个(实际上是三个)原因:

  1. append达到容量后立即返回一个新切片。因此,分配appendInt不会做任何事情。

  2. appendInt同时运行,因此:

    • 只要appendInt不发消息main说它完成了, main不知道什么时候intSlice有你想要的所有值。
    • 您必须等待所有 goroutine 在结束时返回main

问题一:在函数中修改切片

您可能知道在 Go 中,您传递给函数的每个值都会被复制。参考值(例如切片)也被复制,但在内部具有指向原始内存位置的指针。这意味着您可以在函数中修改切片的元素。你不能做的是用一个新的切片重新分配这个值,因为内部指针会指向不同的地方。你需要指针。示例(播放):

func modify(s *[]int) {
    for i:=0; i < 10; i++ {
        *s = append(*s, i)
    }
}

func main() {
    s := []int{1,2,3}
    modify(&s)
    fmt.Println(s)
}

问题 2:同步 goroutines

要等待启动的 goroutine,您可以使用sync.WaitGroup. 示例(播放):

func modify(wg *sync.WaitGroup, s *[]int) {
    defer wg.Done()
    for i:=0; i < 10; i++ {
        *s = append(*s, i)
    }
}

func main() {
    wg := &sync.WaitGroup{}
    s := []int{1,2,3}

    wg.Add(1)
    go modify(wg, &s)

    wg.Wait()
    fmt.Println(s)
}

上面的示例等待(使用wg.Wait()modify完成(完成时modify调用wg.Done())。如果您删除wg.Wait()呼叫,您将看到为什么不同步是一个问题。输出比较:

  • wg.Wait()[1 2 3 0 1 2 3 4 5 6 7 8 9]
  • 没有wg.Wait()[1 2 3]

主 goroutine 比 goroutine 更早返回,modify这就是为什么你永远不会看到修改后的结果。因此同步是绝对必要的。

传达新切片的一个好方法是使用通道。您不需要使用指针,并且可以进行同步。示例(播放):

func modify(res chan []int) {
    s := []int{}
    for i:=0; i < 10; i++ {
        s = append(s, i)
    }
    res <- s
}

func main() {
    c := make(chan []int)
    go modify(c)

    s := <-c
    fmt.Println(s)
}
于 2013-11-06T18:10:07.620 回答