今回は小ネタです。
Goのif文には、以下のように代入文が書けることは有名です。
if err := f(); err != nil {
// error handling
}
言語仕様を見てみると、以下のようにExpression
の前に、オプションでSimpleStmt
が書けるようになっています。
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
SimpleStmt
についても、言語仕様を確認すると、以下の様な定義になっています。
このうちのShortVarDecl
がerr := f()
にあたります。
SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
SendSmt
とかもあるので、使いみちはわかりませんが、以下のように書けます。
package main
import (
"fmt"
)
func main() {
ch := make(chan struct{})
go func() {
if ch <- struct{}{}; true {
fmt.Println("send")
}
}()
<-ch
}
さて本題ですが、IfStmt
の定義を見ると、else
の後にさらにIfStmt
が書けます。
つまり、同じようにオプションでelse if
の後に、SimpleStmt
が書けるということです。
言語仕様をみると、なんだか当たり前なんですが、割りと便利なのではないかなと思います。
例えば、以下のように書けます。
b
は最初のelse if
より下のelse
でも使えます。
else if
のSimpleStmt
でa
を使っているのがポイントです。
package main
import (
"fmt"
)
func f() interface{} {
return "hi"
}
func g(a interface{}) interface{} {
return "hello"
}
func main() {
if a := f(); a == nil {
fmt.Println("a is nil")
} else if b := g(a); b == nil {
fmt.Println("b is nil")
} else {
fmt.Println(a, b)
}
}
上記と同じことをswitch - case
で実現するのは難しいです。
以下のように言語仕様を見ると、switch
の隣にはSimpleStmt
が書けますが、case
に書けるのはExpressionList
だからです。
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .
案外知らない人もいるかもしれないので、ぜひ試してみてください。