Go specのFor statementsを見てみましょう。
for
文は_ブロックの実行を繰り返します。単独の条件文か、for
節か、range
節かによってコントロールされるという3つのフォームがあります。_
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .
これはGoのシンタックスに則っていません。EBNFというものです。EBNFはコンピューター言語についての文で使われます。
package main
import (
"fmt"
)
func main() {
x := 1
for x < 10 {
fmt.Println(x)
x++
}
fmt.Println("done.")
}
for statementsをさらに見ていくと、for節を伴うfor文というものがあります。このような感じです。
for i := 0; i < 10; i++ {
f(i)
}
これはこのように説明されています。
for節を伴う"for"文はその条件や、変数割り当て、インクリメントやデクリメントといった初期化、後処理によってもコントロールされます。
これがEBNFでの例です。
ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
例に当てはめると、i := 0
がInitStmt
、i < 10
がCondition
、i++
がPostStmt
になります。
さらにこのように書かれています。
初期化は短縮形宣言演算子によってされることが多いですが後処理では使ってはいけません。初期化で宣言された変数はイテレーションごとに再利用されます。
これは初期化で宣言された変数はイテレーションごとに再利用されることと、後処理では短縮形宣言演算子を使ってはいけないことを再度明らかにしているものです。
もし空でない初期化が最初のイテレーションのための条件評価の前に実行されれば、後処理はブロックが実行された後に毎回実行されます。
つまり、例えばi := 0
という初期化が最初に実行されます。その後、i < 10
という条件が評価され、_さらにその後_ブロックが実行され、後処理が実行されます。
ループを抜ける別の方法を見てみましょう。break
で抜けることができます。
package main
import (
"fmt"
)
func main() {
x := 1
for {
if x > 9 {
break
}
fmt.Println(x)
x++
}
fmt.Println("done.")
}
これはfor
だけを使って見る例でもあります(初期化、条件、後処理なし)。
Go Specificationもそうですが、Effective Goも良いGoドキュメントです。Effective GoでのForを見てみましょう。
GoのforループはC言語のものに似ていますが同じではありません。forとwhileを一つにしてdo-whileをなくしたようなものです。3つのフォームがあり、そのうち1つだけにセミコロンが必要です。
// C言語のforスタイル
for init; condition; post { }
// C言語のwhileスタイル
for condition { }
// C言語のfor(;;)スタイル
for { }
Effective Goは実践的な内容ですが、Go Specificationは内部でどう動くかを深く説明することに重点を置いています。これら2つのドキュメントはGoを深く学ぶのにとても有用です。