else ifにも代入文が書ける #golang

September 1, 2016

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

今回は小ネタです。 Goのif文には、以下のように代入文が書けることは有名です。

if err := f(); err != nil {
    // error handling
}

言語仕様を見てみると、以下のようにExpressionの前に、オプションでSimpleStmtが書けるようになっています。

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .

SimpleStmtについても、言語仕様を確認すると、以下の様な定義になっています。 このうちのShortVarDeclerr := f()にあたります。

SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .

SendSmtとかもあるので、使いみちはわかりませんが、以下のように書けます。

Go Playgroundで見る

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 ifSimpleStmtaを使っているのがポイントです。

Go Playgroundで見る

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" .

案外知らない人もいるかもしれないので、ぜひ試してみてください。