golang do-while でぐぐると
C の
hoge.c
do {
ループしたい処理
} while (cond);
をどう書くのがいいのかなって golang do-while
でぐぐってみると、だいたい
hoge.go
for {
ループしたい処理
if !cond {
break
}
}
って書き方が出てきて微妙な気分になるのだが、Go の場合
hoge.go
for func() bool {
ループしたい処理
return cond
}() {
}
でもいいんじゃないっすかね。一見しただけでは do-while だと分かりにくいのが玉に瑕。
リトライ処理
ところで、こういうフローが必要になる場合ってだいたいがリトライ処理なのだが、困ったことにリトライ処理を書く場合には do-while でも微妙に痒いところに手が届かなくて、C でも
hoge.c
for (;;) {
ここで複雑な処理
if (!needRetry) break;
log("リトライすっぺ");
awesomesleep(interval);
interval += interval; // exponential backoff
}
って書くのもなんだしなあと結局
hoge.c
retry:
ここで複雑な処理
if (needRetry) {
log("リトライすっぺ");
awesomesleep(interval);
interval += interval; // exponential backoff
goto retry;
}
みたいに goto 使って書いたりするのだが、上の書き方なら
hoge.go
for func() bool {
ここで複雑な処理
if errors.Is(err, tempBusy) {
return true // リトライするよ
} else {
return false // リトライしないよ
}
}() {
log("リトライすっぺ")
awesomesleep(interval)
interval += interval // exponential backoff
}
という風に書けるし、goto が要らなくなってダイクストラ師もニッコリ。
注意点
単なるループとは return や defer の振る舞いが変わる点だけは注意な。もっとも、defer に関しては、ループの中で defer 使うのはだいたいアンチパターンだし、むしろ func で括ることにより「ループが回るたびに毎回 defer が実行されて便利」まであるのでデメリットとも言い難い。return の方はマジ不便な場合もあるので、その時はしょうがないので「無限 for ループを if で break する方」を選ぶなりなんなりしてくらはい。
あとは毎回関数呼び出しされるオーバーヘッドとかあるけど、それが気になる人は Go 使わんでしょ(暴言)。