如何在同一循环中向通道发送值或从通道接收值?

Here is an example:

func main() {
    c := make(chan int)
    i := 0

    go goroutine(c)

    c <- i
    time.Sleep(10 * time.Second)

}

func goroutine(c chan int) {
    for {
        num := <- c
        fmt.Println(num)
        num++
        time.Sleep(1 * time.Second)
        c <- num
    }
}

What I'm trying to do inside of goroutine is to receive number from channel, print it, increment and after one second send it back to the channel. After this I want to repeat the action.

But as a result, operation is only done once.

Output:

0

Am I doing something wrong?

By default the goroutine communication is synchronous and unbuffered: sends do not complete until there is a receiver to accept the value. There must be a receiver ready to receive data from the channel and then the sender can hand it over directly to the receiver.

So channel send/receive operations block until the other side is ready:

1. A send operation on a channel blocks until a receiver is available for the same channel: if there’s no recipient for the value on ch, no other value can be put in the channel. And the other way around: no new value can be sent in ch when the channel is not empty! So the send operation will wait until ch becomes available again.

2. A receive operation for a channel blocks until a sender is available for the same channel: if there is no value in the channel, the receiver blocks.

This is illustrated in the below example:

package main
import "fmt"

func main() {
    ch1 := make(chan int)
    go pump(ch1) // pump hangs
    fmt.Println(<-ch1) // prints only 0
}

func pump(ch chan int) {
    for i:= 0; ; i++ {
        ch <- i
    }
}

Because there is no receiver the goroutine hangs and print only the first number.

To workaround this we need to define a new goroutine which reads from the channel in an infinite loop.

func receive(ch chan int) {
    for {
        fmt.Println(<- ch)
    }
}

Then in main():

func main() {
    ch := make(chan int)
    go pump(ch)
    go receive(ch)
}

Go Playground

You use unbuffered channel, so your goroutine hang on c <- num
You should use buffered channel, like this: c := make(chan int, 1)

Try it on the Go playground

You create an unbuffered channel c with

c := make(chan int)

On unbuffered channels, operations are symmentrical, i.e. every send on a channel needs exactly one receive, every receive needs exactly one send. You send your i into the channel, the goroutine receives it into num. After that, the goroutine sends the incremented num into the channel, but nobody is there to receive it.

In short: The statement

c <- num

will block.

You could use a 1-buffered channel, that should work.

There is another problem with your code that you solved by waiting ten seconds in main: You don't know when your goroutine finishes. Typically, a sync.WaitGroup is used in these situations. But: Your goroutine does not finish. It's idiomatic to introduce a chan struct{} that you close in your main goroutine after a while and select over both channels in the worker goroutine.