ユーザ用ツール

サイト用ツール


tutorial:nim:control_flow

制御フロー

プログラムの流れを制御するための構造を制御フローと呼ぶことにします。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ではブロックを表現するためにオフサイドルールを採用しています。すなわち、インデントが意味を持つことになります。慣習として、インデントは2つの空白文字が使われます。TAB文字は使えません。

elifelseによって、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が満たされる間はループし続けます。

tutorial/nim/control_flow.txt · 最終更新: 2024/08/20 02:05 by freemikan

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki