Selection inside goroutine evaluates every other expression

While playing with Go's channels and routines, I came across special behaviors that I was hoping someone could explain.

Below is a short program that should print a couple of lines in stdout by sending lines through a pipe to a "listener" (select statement), which works in a separate version of goroutine.

package main import ( "fmt" "time" ) func main() { a := make(chan string) go func() { for { select { case <-a: fmt.Print(<-a) } } }() a <- "Hello1\n" a <- "Hello2\n" a <- "Hello3\n" a <- "Hello4\n" time.Sleep(time.Second) } 

Using

 go func() { for s := range a { fmt.Print(s) } }() // or even simpler go func() { for { fmt.Print(<-a) } }() 

works as expected. However, running the topmost fragment using the select statement leads to the following output:

 Hello2 Hello4 

i.e. only every other expression is printed. What witchcraft is this?

+6
source share
3 answers

In the topmost snippet, you extract two values ​​from the channel for each loop. One in the select statement and one in the print statement. A.

Change

  select { case <-a: fmt.Print(<-a) 

For

  select { case val := <-a: fmt.Print(val) 

http://play.golang.org/p/KIADcwkoKs

+12
source
 <-a 

gets the value from the channel, destructive. Thus, in your code you get two values: one in the select statement and one for printing. The one received in the select statement is not bound to any variable and is therefore lost.

Try

 select { case val := <-a: fmt.Print(val) 

instead, to get only one value, bind it to the val variable and print it.

+7
source
 package main import ( "fmt" "time" ) func main() { a := make(chan string) go func() { for { select { case v:= <-a: fmt.Print(v) } } }() a <- "Hello1\n" a <- "Hello2\n" a <- "Hello3\n" a <- "Hello4\n" time.Sleep(5*time.Second) } 
0
source

All Articles