特殊形式による式評価について
元ネタが Zenn の記事だし小ネタだし,どちらで書こうか悩んだが,今まで書いたことがない切り口な気がするので,こっち側で。
いきなりだが,以下のコードを起点に話を始めよう。
package main
import "fmt"
func main() {
ageMap := map[string]uint{
"Alice": 18,
"Teles": 20,
}
fmt.Println(ageMap["Alice"])
// Output
// 18
}
このコードをみて分かるように,インデックス式 ageMap[x]
の評価結果は uint
型になっている(インデックス値が存在しない場合はゼロ値がセットされる)。
まぁ,当たり前だよね。
ところが ageMap[x]
の評価結果を (uint, bool)
の組(tuple)で受けることもできるのだ1。
これによってコードを
package main
import "fmt"
func main() {
ageMap := map[string]uint{
"Alice": 18,
"Teles": 20,
}
if age, ok := ageMap["Selene"]; ok {
fmt.Println(age)
} else {
fmt.Println("unknown")
}
// Output
// unknown
}
と書き換えることでき, ageMap[x]
の評価に失敗した際の挙動を記述できる。
Go の言語仕様では,これを「特殊形式(special form)」と呼んでいる(日本語が怪しいのはご容赦)。
言語仕様を眺めてみると,この特殊形式が適用可能なのは以下の3つのみのようだ。
# | Expressions | Normal Form | Special Form |
---|---|---|---|
1 | Index Expression on Map | foo := bar[x] |
foo, ok := bar[x] |
2 | Type Assertion | foo := bar.(T) |
foo, ok := bar.(T) |
3 | Receive Expression | foo := <-ch |
foo, ok := <-ch |
最初のはインデックス値 x
が map にない場合に false
になる。
2番目は型 T
でのアサーションに失敗した場合に(panic を吐くことなく) false
になる。
最後のはチャネル ch
が閉じている場合に false
になる。
他の式評価や関数の返り値ではこのようなことはできない。 たとえば slice のインデックス式評価に特殊形式はない。 インデックス値が範囲外なら単に panic が投げられるだけだ。
実は,特殊形式が上の3つの式評価でしか適用されないというのが分からなくて「どうして普通の関数の返り値とかではできないんだろう」とひとしきり悩んだことがあったのだった。 言語仕様を読めっての(笑)
ブックマーク
- The Go Programming Language Specification - The Go Programming Language
- Goの言語仕様書精読のススメ & 英語彙集
- Go言語における式の評価文脈を理解する
参考図書
- プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- Alan A.A. Donovan (著), Brian W. Kernighan (著), 柴田 芳樹 (翻訳)
- 丸善出版 2016-06-20
- 単行本(ソフトカバー)
- 4621300253 (ASIN), 9784621300251 (EAN), 4621300253 (ISBN), 9784621300251 (ISBN)
- 評価
著者のひとりは(あの「バイブル」とも呼ばれる)通称 “K&R” の K のほうである。この本は Go 言語の教科書と言ってもいいだろう。
-
厳密には,特殊形式
(T, bool)
の2要素目は型付けなしの真偽値(untyped boolean)に評価される。「型付けなし(untyped)」というのは Go 特有の概念だそうで,具体的な型が決定される前の状態を指す。たとえば,定数math
.Pi
は10進数64桁の小数点数で定義されている。型付けなし定数については『プログラミング言語Go』の3.6.2章にも解説がある。 ↩︎