====== 制御フロー ======
プログラムの流れを制御するための構造を制御フローと呼ぶことにします。Nimの制御フローには、条件分岐とループに大別できます。条件分岐にはifとcaseがあります。ループにはwhileとforがあります。
===== if文 =====
条件によってプログラムの流れを制御するには、if文を使います。if文は次のように書きます。
let x = 99
if x < 100:
echo "x is less than 100"
このプログラムを実行すると、//x is less than 100//と出力されます。''let x = 99''のところを''let x = 100''とすると、何も出力されなくなります。
Nimではブロックを表現するために[[wpjp>オフサイドルール]]を採用しています。すなわち、インデントが意味を持つことになります。慣習として、インデントは2つの空白文字が使われます。TAB文字は使えません。
''elif''と''else''によって、if文の条件を満たさなかったときに実行されるブロックを追加することが出来ます。
let x = 200
if x < 100:
echo "x is less than 100"
elif x < 200:
echo "x is less than 200"
elif x < 300:
echo "x is less than 300"
else:
echo "otherwise"
このプログラムを実行すると、//x is less than 300//と出力されます。''let x = 200''のところを''let x = 300''とすると、//otherwise//が出力されます。''else''は全ての条件を満たさなかったときに実行されるブロックです。
===== case文 =====
条件分岐にはもう一つcase文があります。一つの変数に対して多数の条件で処理を分岐する場合には、if文よりもcase文の方が適しています。先のifを使った例は、次のように書き換えられます。
let x = 200
case x
of low(int)..99:
echo "x is less than 100"
of 100..199:
echo "x is less than 200"
of 200..299:
echo "x is less than 300"
else:
echo "otherwise"
''low(int)''は、int型の最小の値を返します。''..''による範囲の指定には、両端の値が必要です。負の値を含めた全ての100より小さい範囲をカバーするためにこのようなやや冗長な記述をしています。
この場合、elseのブロックは必須です。case文では、条件となる値の全てのケースをカバーしなければなりません。カバーしていない場合はコンパイルエラーとなります。
let x = 100
case x
of 0..99:
echo "x is less than 100"
コンパイルすると次のようなエラーになります。
Error: not all cases are covered
elseで何もやることがない場合は、''discard''という特殊な命令を使います。
let x = 100
case x
of 0..99:
echo "x is less than 100"
else:
discard
このプログラムは正常にコンパイルされ、実行すると何も出力されません。
case文では、範囲以外にも複数の値を一つの分岐に使用したり、
let x = 100
case x
of 10, 100, 1000:
echo "x is power of 10 (but limited to very small range)"
else:
discard
文字列を条件に使用したり出来ます。
let s = "hello"
case s
of "":
echo "nothing to say"
of "hello", "good-bye":
echo "You say ", s
else:
discard
===== while文 =====
while文は条件が成立する間、ブロックを実行し続けます。
var x = 0
while x < 10:
echo "hello", x
x += 1
実行すると、次の出力が得られます。
hello0
hello1
hello2
hello3
hello4
hello5
hello6
hello7
hello8
hello9
条件には、任意の式を使用することが出来ます。
===== for文 =====
for文は、while文よりも一定のパターンに従ったループを表現するのに適しています。先のwhileループをforループに置き換えると次のようにまります。
for i in countup(0, 9):
echo "hello", i
あるいは、次のようにも出来ます。
for i in 0..<10:
echo "hello", i
どちらも先のwhileループと同じ出力が得られます。
''in''と'':''の間に来るのは、イテレーターです。イテレーターを返すものなら何でも使えるので、適用できるケースは多くあります。例えば、配列の要素を順に走査することができます。
for fruit in ["apple", "orange", "grape"]:
echo fruit
このプログラム実行すると、次の出力が得られます。
apple
orange
grape
インデックスと値を同時に取得することも出来ます。
for (i, fruit) in ["apple", "orange", "grape"].pairs:
echo i, " => ", fruit
このプログラム実行すると、次の出力が得られます。
0 => apple
1 => orange
2 => grape
他にもいろいろなケースがあります。
===== break文とcontinue文 =====
break文はループを終了します。
var x = 0
while true:
if x < 10:
echo x
else:
break
inc x
このプログラムを実行すると、次の出力が得られます。
0
1
2
3
4
5
6
7
8
9
continue文は、現在のブロックの残りの処理をスキップして、次のループ開始位置まで戻ります。
for x in 0..<10:
if x %% 2 == 0:
continue
echo x
このプログラムを実行すると、次の出力が得られます。
1
3
5
7
9
break文もcontinue文も、対象となるループ文は現在実行している位置の直近のループ文のみであることに注意してください。
var x = 0
while x < 10:
while true:
if x %% 3 == 0:
echo x
else:
break # もっとも内側のwhileから抜ける
inc x
inc x
このブログラムを実行すると、次の出力が得られます。
0
3
6
9
外側のwhile文からは抜け出ませんので、外側のwhileの条件である''x < 10''が満たされる間はループし続けます。