36

I saw some code in this link, and got confused:http://www.darkcoding.net/software/go-lang-after-four-months/

What's the meaning of the second value(ok)?

for self.isRunning {

    select {
    case serverData, ok = <-fromServer:   // What's the meaning of the second value(ok)?
        if ok {
            self.onServer(serverData)
        } else {
            self.isRunning = false
        }

    case userInput, ok = <-fromUser:
        if ok {
            self.onUser(userInput)
        } else {
            self.isRunning = false
        }
    }

}
2
  • It seems to me that's a too heavy construct. With select, I think there is no need to fetch the ok boolean. Or am I missing something ? Commented May 3, 2012 at 18:16
  • 4
    They are orthogonal. "ok" in the channel receive operation indicates whether the channel is closed. Select just waits until at least one of its cases can run, and then picks one at random without regard to whether the channel is closed. A default case makes it non-blocking. Commented May 6, 2012 at 19:46

4 Answers 4

45

The boolean variable ok returned by a receive operator indicates whether the received value was sent on the channel (true) or is a zero value returned because the channel is closed and empty (false).

The for loop terminates when some other part of the Go program closes the fromServer or the fromUser channel. In that case one of the case statements will set ok to true. So if the user closes the connection or the remote server closes the connection, the program will terminate.

http://play.golang.org/p/4fJDkgaa9O:

package main

import "runtime"

func onServer(i int) { println("S:", i) }
func onUser(i int)   { println("U:", i) }

func main() {
    fromServer, fromUser := make(chan int),make(chan int)
    var serverData, userInput int
    var ok bool

    go func() {
        fromServer <- 1
        fromUser <- 1
        close(fromServer)
        runtime.Gosched()
        fromUser <- 2
        close(fromUser)
    }()

    isRunning := true
    for isRunning {
        select {
            case serverData, ok = <-fromServer:
                if ok {
                    onServer(serverData)
                } else {
                    isRunning = false
                }

            case userInput, ok = <-fromUser:
                if ok {
                    onUser(userInput)
                } else {
                    isRunning = false
                }
            }
        }
        println("end")
}
Sign up to request clarification or add additional context in comments.

3 Comments

What does empty mean in this case ? Closed is easy but does empty mean that nobody is writing right now ??
@Kr0e If a channel is closed but it is still containing some items it is possible to receive from it and ok is true. But it is impossible to write to a closed channel (this is a definition of "closed channel" in fact). When a channel had been closed by producer goroutine and drained by consumer than ok is false. Empty and closed, just like it said.
In that case one of the case statements will set ok to true. Don't you mean false?
13

A couple of answers have cited the spec on the receive operator, but to understand you probably need to read the spec on the close function as well. Then since you'll be wondering why these features are the way they are, read how the for statement ranges over a channel. The for statement needs a signal to stop iteration and close is the way a sender can say "no more data".

With close and , ok = <- exposed as part of the language, you can use them in other cases when you wish a sending goroutine to signal "no more data". The example code in the question is an interesting use of these features. It is handling both a "server" channel and a "user" channel, and if a "no more data" signal arrives from either of them, it breaks out of the loop.

1 Comment

You are totally right.The multi-valued receive operation returns a received value along with an indication of whether the channel is closed.
3

See the relevant section in the Go language spec: http://golang.org/ref/spec#Receive_operator

Comments

0

In Go, functions & channels can return more than 1 value. Here ok must be a boolean variable with true (successful) and false (unsuccessful) and serverData is the actual data received from the channel.

5 Comments

That's the same construct for maps.
I'm still confused. I don't understand when the second return is false? I think if a channel is empty, it will block. And if a channel is not block, it must return successfully.
to clarify that, I guess we need to see more of the code, i.e what is the channel fromServer actually doing, etc..
@hardPass: it will return false if the channel is closed and empty
@Chaos, you are incorrect. Channels cannot receive or emit multiple values.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.