Go 通道将每个字母作为字符串而不是整个字符串

Go channel takes each letter as string instead of the whole string

我正在创建一个采用字符串值的简单通道。但显然我在每个循环中推送字符串中的每个字母而不是整个字符串。

我可能遗漏了一些非常基本的东西。我做错了什么?

https://play.golang.org/p/-6E-f7ALbD

代码:

func doStuff(s string, ch chan string) {
    ch <- s
}

func main() {
    c := make(chan string)
    loops := [5]int{1, 2, 3, 4, 5}

    for i := 0; i < len(loops); i++ {
        go doStuff("helloooo", c)
    }

    results := <-c

    fmt.Println("channel size = ", len(results))

    // print the items in channel
    for _, r := range results {
        fmt.Println(string(r))
    }
}

您的代码在频道上正确发送 strings:

func doStuff(s string, ch chan string){
    ch <- s
}

问题出在接收端:

results := <- c

fmt.Println("channel size = ", len(results))

// print the items in channel
for _,r := range results {
  fmt.Println(string(r))
}

results 将是从通道接收的 单个 值(发送的第一个值)。然后你打印这个 string.

的长度

然后你使用 for range 循环遍历这个字符串 (results),循环遍历它的 runes,然后你打印那些。

你想要的是循环通道的值:

// print the items in channel
for s := range c {
    fmt.Println(s)
}

这 运行 将导致 运行 时间恐慌:

fatal error: all goroutines are asleep - deadlock!

因为您永远不会关闭频道,并且频道 运行 上的 for range 直到频道关闭。所以你必须在某个时候关闭频道。

例如让我们等待 1 秒,然后关闭它:

go func() {
    time.Sleep(time.Second)
    close(c)
}()

这样您的应用程序将 运行 并在 1 秒后退出。在 Go Playground.

上试用

另一个更好的解决方案是使用 sync.WaitGroup:这会等待所有 goroutine 完成它们的工作(在通道上发送一个值),然后关闭通道(因此没有不必要的等待 /延迟)。

var wg = sync.WaitGroup{}

func doStuff(s string, ch chan string) {
    ch <- s
    wg.Done()
}

// And in main():
for i := 0; i < len(loops); i++ {
    wg.Add(1)
    go doStuff("helloooo", c)
}
go func() {
    wg.Wait()
    close(c)
}()

Go Playground 上试试这个。

备注:

要重复某事 5 次,您不需要那个难看的 loops 数组。简单地做:

for i := 0; i < 5; i++ {
    // Do something
}

你取回字母而不是字符串的原因是你将通道结果分配给一个变量并迭代分配给这个变量的通道结果,在你的例子中是一个字符串,而在 Go 中您可以使用 for range 循环遍历字符串以获取符文。

您可以简单地打印频道而无需迭代频道结果。

package main

import (
    "fmt"
)

func doStuff(s string, ch chan string){
    ch <- s
}

func main() {
    c := make(chan string)
    loops := [5]int{1,2,3,4,5}

    for i := 0; i < len(loops) ; i++ {
       go doStuff("helloooo", c)    
    }

    results := <- c 
    fmt.Println("channel size = ", len(results))
    fmt.Println(results) // will print helloooo
}