Go OR-Done-Channel Pattern: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
|||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=External= | |||
=Internal= | =Internal= | ||
* [[Go_Channels#Use_a_done_Channel| | * [[Go_Channels#Use_a_done_Channel|The <tt>done</tt> Channel]] | ||
* [[Go_Channels#Channel_Patterns|Channel Patterns]] | |||
=Overview= | =Overview= | ||
Line 21: | Line 23: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=<tt>orDone( | =<tt>orDone()</tt>= | ||
<syntaxhighlight lang='go'> | <syntaxhighlight lang='go'> | ||
// orDone iterates over the input channel 'in', sending the incoming elements to the output channel returned | |||
// as the result of the function, until the 'done' channel is messaged (written onto or closed). | |||
func orDone(done <-chan interface{}, in <-chan interface{}) <-chan interface{} { | |||
var out = make(chan interface{}) | |||
go func() { | |||
defer close(out) | |||
for { | |||
select { | |||
case <-done: | |||
// the 'done' channel was messaged, exit the closure, which will close the output channel | |||
return | |||
case v, inputChanStillOpen := <-in: | |||
if !inputChanStillOpen { | |||
// input channel closed, exit the closure, which will close the output channel | |||
return | |||
} | |||
out <- v | |||
} | |||
} | |||
}() | |||
return out | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> |
Latest revision as of 23:06, 5 February 2024
External
Internal
Overview
Reading from a channel until the channel is closed can be done by ranging over a channel:
for v := range c {
// do something with the channel value, we exit the loop automatically when the channel is closed
...
}
The for
/range
syntax is simple and intuitive, but it cannot be used anymore if we want to make the loop preemptable by using a done
channel. In that case we need to replace it with a for
/select
syntax and case
for the state of the done
channel (see an example here).
The equivalent syntax is:
for v := range orDone(done, c) {
// do something with the channel value, we exit the loop automatically when the 'c' channel is closed
// or when the 'done' channel is messaged (written onto or closed)
...
}
orDone()
// orDone iterates over the input channel 'in', sending the incoming elements to the output channel returned
// as the result of the function, until the 'done' channel is messaged (written onto or closed).
func orDone(done <-chan interface{}, in <-chan interface{}) <-chan interface{} {
var out = make(chan interface{})
go func() {
defer close(out)
for {
select {
case <-done:
// the 'done' channel was messaged, exit the closure, which will close the output channel
return
case v, inputChanStillOpen := <-in:
if !inputChanStillOpen {
// input channel closed, exit the closure, which will close the output channel
return
}
out <- v
}
}
}()
return out
}