I have some concurrent code that has two different timeout intervals, one static and one dynamic. I want to react the same way to both of them. This is the gist of it:
select {
case <-time.After(staticTimeoutInterval):
doSomething()
case <-time.After(dynamicTimeoutInterval):
doSomething()
}
Is there any way to write doSomething() only once? It's strange that select
isn't as flexible as switch
in this respect.
In your specific case you can use something like
timeout := min(staticTimeoutInterval, dynamicTimeoutInterval)
select {
case <-time.After(timeout):
doSomething()
}
func min(a, b time.Duration) int {
if a < b {
return a
}
return b
}
About the seemingly inconsistent treatment of switch
and select
- while these statements have similar syntax, the purpose of switch
is branched execution, while the purpose of select
is communication.
If I can exaggerate:
switch
is about the part after the case
expression - the case
expression here is mostly a simple, side-effect free expressionselect
is about the part in the case
expression - the case
expression here provides you with the important communication side effect and is not trivial to implement at allAllowing fallthrough in select
will allow you to save a couple of lines in some cases, but it will often make select
statements harder to reason about. Given a similar choice in other situations, the Go creators have almost always gone with more verbose but simpler to understand.
What you got looks right. select
cases do not fall through. And if it did, it would remove clarity and result in the same number of lines of code.