转到频道将每个字母作为字符串而不是整个字符串

I'm creating a simple channel that takes string values. But apparently I'm pushing each letter in the string instead of the whole string in each loop.

I'm probably missing something very fundamental. What am I doing wrong ?

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

Code:

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))
    }
}

Your code sends strings on the channel properly:

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

The problem is at the receiver side:

results := <- c

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

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

results will be a single value received from the channel (the first value sent on it). And you print the length of this string.

Then you loop over this string (results) using a for range which loops over its runes, and you print those.

What you want is loop over the values of the channel:

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

This when run will result in a runtime panic:

fatal error: all goroutines are asleep - deadlock!

Because you never close the channel, and a for range on a channel runs until the channel is closed. So you have to close the channel sometime.

For example let's wait 1 second, then close it:

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

This way your app will run and quit after 1 second. Try it on the Go Playground.

Another, nicer solution is to use sync.WaitGroup: this waits until all goroutines are done doing their work (sending a value on the channel), then it closes the channel (so there is no unnecessary wait / delay).

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)
}()

Try this one on the Go Playground.

Notes:

To repeat something 5 times, you don't need that ugly loops array. Simply do:

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

The reason you are getting back the letters instead of string is that you are assigning the channel result to a variable and iterating over the result of the channel assigned to this variable which in your case is a string, and in Go you can iterate over a string with a for range loop to get the runes.

You can simply print the channel without to iterate over the channel result.

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
}