My External Storage

Nov 10, 2019 - 3 minute read - Comments - Go

[Go] タグなし switchは switch true {...}と等しい

先日のgolang.tokyoではswitch文に関するDevquizが出題された。 私はわかっていたつもりで乾杯の挨拶中に解説を話したが、間違えた解説だったので改めて仕様を確認した。

TL;DR

  • 先日のgolang.tokyoのDevquizの解説で誤った解説をしてしまった
  • Goのswitch文は条件以外に、switch内にスコープを絞ったStatementを書くことができる。
    • switch x := f(); x { ... }
  • Goのswitch文は条件(タグ)なしで書くことができる
    • タグなしswitchtagless-switch)はswitch true

正しい答えは@makki_dさんに会場でも指摘してもらった。

golang.tokyo #27のDevquiz

2019/11/05に行われたgolang.tokyoの抽選では以下のDevquizが出題された。

// 以下のコードを実行すると何が出力されるか答えよ。
package main

import "fmt"

func main() {
    switch ok := false; {
    case true:
        fmt.Println("true", ok)
    case false:
        fmt.Println("false", ok)
    default:
        fmt.Println("default")
    }
}

何が出力されるかというと、true falseが出力される。
私はこれを「case trueが常に真として評価されるからtrue falseが出力される。」と解説したがそれは誤りだった。

switch文の言語仕様について

switch文の言語仕様は以下で確認することができる。

Devquizのswitch文はtype switchではないので、ExprSwitchStmtとなる。

SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .

switch内にスコープを絞ったStatementを書ける

ExprSwitchStmtの定義を見ればわかる通り、switch文は実際にswitch文で評価したい式(Expression)と別に代入などの文(SimpleStmt)を含むことができる。

Devquiz中のswitch文もSimpleStmtとして、代入式を含んでいた

switch ok := false; {

Goのswitch文は式(タグ)なしで書くことができる

わかる人はもうわかっただろうが、Devquizのswitch文には式が含まれていない。これはGoの文法的に間違いではない。

There can be at most one default case and it may appear anywhere in the “switch” statement. A missing switch expression is equivalent to the boolean value true.

式が含まれていないswitch文はswitch trueとして条件評価が行われる。
よって、 今回のDevquizは「switch trueというswitch文だったので、case true:という条件が真になっていた」のが正しい解説となる。
switch ok := false; ok {と書けばok変数の値と各caseの値が比較され、(人間がパット見考える)期待どおりの挙動となる。

なお、switch {...}のような、式がないswitch文のことを、“タグなしswitch"(tagless-switch)と呼ぶ。
タグなしswitchの評価がswitch trueになることはプログラミング言語Goでもしっかり明記されている。

終わりに

2,3か月に1回くらいの割合でGoの言語仕様を読んでいる気がする。
Goの言語仕様はこの1ページだけだし、文中のキーワードにはリンクが付いているので勉強しやすい。
毎回忘れてやり直している気がするが、ExpressionStatementの違いも頭に入ってきた。

参考

関連記事