ここではVB.NETの繰り返し(ループ)ステートメントについて見ていきます。 VB.NETには、

の4つのループ構文が用意されています。 またExitによってループの中断Continueによってループのスキップを行うことができます。

§1 For-Nextステートメント

Forステートメントは繰り返す回数が決まっている場合に使用します。 Forステートメントでは今何回繰り返したかを覚えておくためのカウンタ変数が必要になります。 構文の形式は次の通りです。

Forステートメントの構文
For カウンタ変数 = 初期値 To 終了値 [Step 増分]
  [ステートメント]
Next [カウンタ変数]

この構文のうち [ ]でくくった部分は省略可能な部分です。

Forステートメントでは、まずカウンタ変数を初期値に指定し、増分で指定した分ずつカウンタ変数の値を増やしていきます。 その度にForから Nextの間に記述されているすべてのステートメントを実行します。 カウンタ変数が終了値に達するか越えた場合、繰り返しが終了します。 このとき増分を省略すると増分は1とされます。

Forステートメントと増分の例
Dim i As Integer ' カウンタ変数

' 0 から 9 まで 1 ずつカウントアップ
For i = 0 To 9
  Console.Write(i)
Next i

Console.WriteLine()

' 9 から 0 まで -1 ずつカウントダウン
For i = 9 To 0 Step -1
  Console.Write(i)
Next

Console.WriteLine()

' 0 から 9 まで 2 ずつカウントアップ
For i = 0 To 9 Step 2
  Console.Write(i)
Next

Console.WriteLine()
実行結果
0123456789
9876543210
02468

ForステートメントではForステートメントの中にさらにForステートメントを含めることもできます。 この場合、内側のForステートメントから順に繰り返されていきます。

入れ子にしたForステートメントの例
Dim i, j As Integer ' カウンタ変数

' i が 0 から 2 まで 1 ずつ
For i = 0 To 2
  ' j が 0 から 2 まで 1 ずつ
  For j = 0 To 2
    Console.WriteLine("i = {0}, j = {1}", i, j)
  Next
Next
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
i = 2, j = 0
i = 2, j = 1
i = 2, j = 2

VB.NET 2003 (Visual Studio .NET 2003)からは、次の例のようにForステートメントで使用できるカウンタ変数をForステートメント内で宣言できるようになりました。

Forステートメント内でカウンタ変数を宣言する例
' 0 から 9 まで 1 ずつ
For i As Integer = 0 To 9
  Console.Write(i)
Next

このようにして宣言したカウンタ変数は、Forステートメント内のみで有効であることに注意してください。 この例の変数iはForステートメントの外から参照することはできません。 カウンタ変数のスコープについてはブロックと変数のスコープも参照してください。

Nextの後ろには対応するForのカウンタ変数を記述することが出来ます。 これは本来省略可能なものですが、多重ループなどの内側の処理が長くなる場合などでは、カウンタ変数を記述することでForステートメントとカウンタ変数の対応が分かりやすくなるようにすることが出来ます。

Nextで対応するカウンタ変数を記述する例
' x を 1 から 3 まで
For x As Integer = 1 To 3
  ' y を 1 から 3 まで
  For y As Integer = 1 To 3
    ' z を 1 から 3 まで
    For z As Integer = 1 To 3
      Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z)
    Next z
  Next y
Next x


§2 For-Each-Nextステートメント

For-Eachステートメントは配列など特定の要素の集まり(コレクション)に対して、そのすべての要素を順番に一つずつ抜き出しながら繰り返す場合に使用します。 For-Eachステートメントでは抜き出した要素を扱うための変数を用意しておく必要があり、その変数の型は当然要素を格納できる型である必要があります。 構文の形式は次の通りです。

For-Eachステートメントの構文
For Each 要素変数 In コレクション
  [ステートメント]
Next [要素変数]

For-EachステートメントはForステートメントをより簡単にしたようなものなので動作は容易に予想できると思います。 次のコードは配列に含まれるすべての要素を抜き出して表示するコードです。

For-Eachステートメントで配列内の各要素を表示する例
' 配列
Dim arr() As Integer = {0, 1, 2, 3, 4, 5}

' 抜き出した要素を格納するための変数
Dim i As Integer

' すべての要素について繰り返す
For Each i In arr
  Console.WriteLine(i)
Next
実行結果
0
1
2
3
4
5

二次元配列に対してFor-Eachステートメントを使用した場合も、一次元配列と同様に1つずつ要素が抜き出されます。

For-Eachステートメントで二次元配列内の要素を表示する例
' 二次元配列
Dim arr(,) As Integer = {{0, 1, 2}, {3, 4, 5}}

' 抜き出した要素を格納するための変数
Dim i As Integer

' すべての要素について繰り返す
For Each i In arr
  Console.WriteLine(i)
Next
実行結果
0
1
2
3
4
5

Forステートメント同様、For-EachステートメントでもVB.NET 2003 (Visual Studio .NET 2003)からは、ステートメント内で使用できる要素変数をステートメント部で宣言できるようになりました。

For-Eachステートメント内で要素変数を宣言する例
' 配列
Dim arr() As Integer = {0, 1, 2, 3, 4, 5}

' すべての要素について繰り返す
For Each i As Integer In arr
  Console.WriteLine(i)
Next

配列・多次元配列の宣言・作成については配列、二次元以上の配列の扱い方については多次元配列・ジャグ配列で解説しています。

For-Eachステートメントで列挙できるもの、列挙するために必要な要件、そして列挙する際の動作などはIEnumerable・IEnumeratorで詳しく解説しています。

§3 While-End Whileステートメント

Whileステートメントは繰り返す回数ではなく、繰り返しを続ける(または、やめる)条件が決まっている場合に使用します。 構文の形式は次の通りです。 VB.NETでは他のブロック構造との整合性を保つためにWendキーワードは使用せず、代わりにEnd Whileを使わなければなりません。

While 条件式
  [ステートメント]
End While

この条件式が成り立っている限り(式が真である限り)繰り返されます。 条件が常に成り立ってしまうようにコーディングすると無限ループしてしまうので注意が必要です。 意図的に無限ループにすることもありますが、その場合でも通常はループを中止するためのコードを記述します。

Dim i As Integer = 0

' i が 5 未満の間はループを繰り返す
While i < 5
  Console.WriteLine(i)

  ' i を 1 増やす
  i += 1
End While
実行結果
0
1
2
3
4

比較のため、Forステートメントを使って上記のコードと同様の動作をするコードを記述すると次のようになります。

Dim i As Integer

For i = 0 To 4 Step 1
  Console.WriteLine(i)
Next

条件式の記述方法についてはIf Then Elseステートメントを参照してください。

§4 Do-Loopステートメント

Do-LoopステートメントはWhileステートメントと似ていますが、Whileとは異なり様々なバリエーションの条件を付けることができます。 その構文を次に示します。

〈先に〉条件をチェックし、条件が〈成り立っている間〉ループを続ける構文
Do While 条件式
  [ステートメント]
Loop
ステートメントを実行した〈後で〉条件をチェックし、条件が〈成り立っている間〉ループを続ける構文
Do
  [ステートメント]
Loop While 条件式
〈先に〉条件をチェックし、条件が〈成り立つまで〉ループを続ける構文
Do Until 条件式
  [ステートメント]
Loop
ステートメントを実行した〈後で〉条件をチェックし、条件が〈成り立つまで〉ループを続ける構文
Do
  [ステートメント]
Loop Until 条件式
〈無限に〉ループを繰り返し、ステートメントを実行する構文
Do
  [ステートメント]
Loop

次の例は、Do-Loop Untilを使った繰り返しの例です。

Dim i As Integer = 0

' i が 5 になるまではループを繰り返す
Do
  Console.WriteLine(i)

  i += 1
Loop Until i = 5
実行結果
0
1
2
3
4

次の例は、上記の例をDo While-Loopを使って書き換えた例です。

Dim i As Integer = 0

' i が 5 未満の間はループを繰り返す
Do While i < 5
  Console.WriteLine(i)

  i += 1
Loop
実行結果
0
1
2
3
4

これは、While-End Whileを使って次のように記述する事もできます。

Dim i As Integer = 0

' i が 5 未満の間はループを繰り返す
While i < 5
  Console.WriteLine(i)

  i += 1
End While

While 条件式、 Until 条件式で条件式を記述しない場合でも、Exitステートメントを使用することでループを中断することができます。

§5 無限ループ

Do-Loopステートメントでは条件式を省略することができ、これを省略すると無限ループとなります。 Do-Loopステートメントを使えばもっともシンプルに無限ループを記述できます。

Do-Loopステートメントによる無限ループの例
' 無限ループ
Do
  ' 停止するまで 'あ' と表示し続ける
  Console.Write("あ")
Loop

C言語で無限ループを記述するのに使われるwhile(1) {...}をVBで記述する場合は、While-End Whileステートメントが使えます。 条件式が常に真となれば無限ループとなるので、次の例ではTrueを使っています。

While-End Whileステートメントによる無限ループの例
' 無限ループ
While True
  ' 停止するまで 'あ' と表示し続ける
  Console.Write("あ")
End While

もう一つ、C言語で使われる無限ループfor(;;) {...}をVBで記述する場合はFor-Nextステートメントが使えます。 ただし、C言語のfor文ではループの終了条件を記述するのに対しFor-Nextステートメントではループの終了値を記述するという違いがあります。 そのため、次の例ようにStep 0を指定して終了値に達することがないようにすることでFor-Nextステートメントで無限ループを記述することが出来ます。

For-Nextステートメントによる無限ループの例
' 無限ループ
For i As Integer = 0 To 1 Step 0
  ' 停止するまで 'あ' と表示し続ける
  Console.Write("あ")
Next

Stepを記述しない代わりに、カウンタ変数の値を元に戻すことで終了値に達しないようにすることでも無限ループを記述出来ます。

For-Nextステートメントによる無限ループの例
' 無限ループ
For i As Integer = 0 To 2
  ' 停止するまで 'あ' と表示し続ける
  Console.Write("あ")

  i -= 1 ' カウントアップした分を戻す
Next

無限ループを記述する場合でも、ある条件を満たした場合にループを抜けたいという場合には、Exitステートメントを使用します。

§6 ループステートメントの中断とスキップ

§6.1 Exitステートメント (ループの中断)

ForやWhileなどのステートメントでは、ループの途中でループから抜けることができます。 その場合にはExitステートメントを使います。 これはCやC#のfor文におけるbreakに相当するものです。 ForループではExit For、WhileループではExit Whileのように使います。

Forループを中断する例
Dim i As Integer

For i = 0 To 9
  Console.WriteLine(i)

  ' i が 5 になったらループを中止
  If i = 5 Then Exit For
Next
実行結果
0
1
2
3
4
Doループを中断する例
Dim i As Integer = 0

' 無限ループ
Do
  i += 1

  Console.WriteLine(i)

  ' i が 3 になったらループから抜ける
  If i = 3 Then Exit Do
Loop
実行結果
1
2
3

§6.1.1 入れ子になっているループとExitステートメント

入れ子になっている(ネストされた)ループ構造の中でExitステートメントを実行する場合は、Exitで指定したものに対応するループ構文のうち、最も内側にあるものが中断される点に注意が必要です。 次の例では二重のForステートメントの内側でExit Forステートメントを実行しています。

二重のForループを中断する例
For i As Integer = 0 To 3
  For j As Integer = 0 To 3
    Console.WriteLine("i = {0}, j = {1}", i, j)

    ' j が 1 になったら内側のjに対するループを中止
    If j = 1 Then Exit For
  Next
Next

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 1
i = 1, j = 0
i = 1, j = 1
i = 2, j = 0
i = 2, j = 1
i = 3, j = 0
i = 3, j = 1
ループ終了

次の例は、先の例を少し変えて、外側をWhileステートメントにし、Forステートメントの内側でExit Whileステートメントを実行しています。

入れ子になったループを中断する例
Dim i As Integer = 0

While i <= 3
  For j As Integer = 0 To 3
    Console.WriteLine("i = {0}, j = {1}", i, j)

    ' j が 1 になったら外側のWhileのループを中止
    If j = 1 Then Exit While
  Next

  i += 1
End While

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 1
ループ終了

この例においてExit Whileの代わりにExit Forとすると内側のForのループを中断するようになり、最初に示したコードと同様の動作となります。

入れ子になったループを中断する例
Dim i As Integer = 0

While i <= 3
  For j As Integer = 0 To 3
    Console.WriteLine("i = {0}, j = {1}", i, j)

    ' j が 1 になったら内側のForのループを中止
    If j = 1 Then Exit For
  Next

  i += 1
End While

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 1
i = 1, j = 0
i = 1, j = 1
i = 2, j = 0
i = 2, j = 1
i = 3, j = 0
i = 3, j = 1
ループ終了

Exitステートメントはここで紹介した繰り返し構文の他にも、プロシージャの中断でも使われます。

§6.1.2 入れ子になっているループからの脱出

Exitステートメントではもっとも内側にあるExitに対応するループを中断することは出来ますが、Exitステートメントだけでは二重のForループを中断するといったことが出来ません。 入れ子になっているループから脱出する方法にはいくつかありますが、その一つは次のようにフラグとExitステートメントを組み合わせる方法です。

フラグとExitステートメントを使ってネストされたループを中断する例
' ループを中断するためのフラグ
Dim exitFor As Boolean = False

For i As Integer = 0 To 3
  For j As Integer = 0 To 3
    Console.WriteLine("i = {0}, j = {1}", i, j)

    ' i が 1 かつ j が 2 になったらループを中断する
    If i = 1 AndAlso j = 2 Then
      ' 外側(i)のループを中断するためのフラグを立てる
      exitFor = True

      ' 内側(j)のループを中断する
      Exit For
    End If
  Next

  ' フラグが真なら、外側(i)のループを中断する
  If exitFor Then Exit For
Next

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
ループ終了

もう一つはExitステートメントの代わりにGoToステートメントを使ってループの外に脱出する方法です。

GoToステートメントを使ってネストされたループを中断する例
For i As Integer = 0 To 3
  For j As Integer = 0 To 3
    Console.WriteLine("i = {0}, j = {1}", i, j)

    ' i が 1 かつ j が 2 になったらループを中断する
    If i = 1 AndAlso j = 2 Then GoTo ExitFor
  Next
Next

ExitFor:

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
ループ終了

もし入れ子になっているループ部分をプロシージャとして分離できるなら、次のようにExit Sub/Functionステートメントを使ってプロシージャごと中断することで入れ子になっているループを中断することも出来ます。 次の例ではExit Subステートメントを使っていますが、当然Returnステートメントを使うことも出来ます。

ネストされたループをプロシージャに分離してループを中断する例
Shared Sub Main()
  ' 二重ループを含むプロシージャを呼び出す
  Test()

  Console.WriteLine("ループ終了")
End Sub

Shared Sub Test()
  For i As Integer = 0 To 3
    For j As Integer = 0 To 3
      Console.WriteLine("i = {0}, j = {1}", i, j)

      ' i が 1 かつ j が 2 になったらプロシージャの処理を中断してループから脱出する
      If i = 1 AndAlso j = 2 Then Exit Sub
    Next
  Next
End Sub
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
ループ終了

上記の例とTry-Finally-End Tryステートメントを組み合わせることで、プロシージャ終了時に処理を行うようにすることも出来ます。

ネストされたループをプロシージャに分離してループを中断する例
Shared Sub Main()
  ' 二重ループを含むプロシージャを呼び出す
  Test()
End Sub

Shared Sub Test()
  Try
    For i As Integer = 0 To 3
      For j As Integer = 0 To 3
        Console.WriteLine("i = {0}, j = {1}", i, j)

        ' i が 1 かつ j が 2 になったらプロシージャの処理を中断してループから脱出する
        If i = 1 AndAlso j = 2 Then Exit Sub
      Next
    Next
  Finally
    ' プロシージャが中断する際に行う処理
    Console.WriteLine("ループ終了")
  End Try
End Sub
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
ループ終了

例外をスローして処理を中断することによりループを脱出する方法も考えられます。 ただし、例外をスローする際のコストや、意図しない例外をキャッチしてしまう可能性等を考慮すると、ループを脱出することだけを目的にして例外をスローするこの方法はあまり推奨できる方法ではありません。

例外をスローすることでネストされたループを中断する例
Try
  For i As Integer = 0 To 3
    For j As Integer = 0 To 3
      Console.WriteLine("i = {0}, j = {1}", i, j)

      ' i が 1 かつ j が 2 になったら例外をスローしてループを中断する
      If i = 1 AndAlso j = 2 Then Throw New Exception()
    Next
  Next
Catch ' ループ内でスローされる例外を捕捉
  Console.WriteLine("ループ終了")
End Try
実行結果
i = 0, j = 0
i = 0, j = 1
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 1
i = 1, j = 2
ループ終了

§6.2 Continueステートメント (ループのスキップ)

VB.NET 2005 (Visual Studio 2005)からはContinueステートメントが使えるようになりました。 Continueステートメントを使うと、ループの途中で残りの処理をスキップし、ループ処理の先頭に戻ることができます。 これはCやC#のfor文におけるcontinueに相当するものです。 Continueステートメントでスキップした場合、Continue以降の処理は実行されなくなります。 Exitステートメントと同様、ForループではContinue For、WhileループではContinue Whileのように使います。

Forループの途中でスキップする例
For i As Integer = 0 To 4
  ' i が 3 の時はスキップ
  If i = 3 Then Continue For

  Console.WriteLine(i)
Next
実行結果
0
1
2
4

ContinueステートメントもExitステートメントと同様に、Continueステートメントで指定したものに対応するループ構文のうち、最も内側にあるものがスキップされます。

入れ子になったForループの途中でスキップする例
For i As Integer = 0 To 3
  For j As Integer = 0 To 3
    ' j が 1 になったら内側のjに対するループをスキップ
    If j = 1 Then Continue For

    Console.WriteLine("i = {0}, j = {1}", i, j)
  Next
Next

Console.WriteLine("ループ終了")
実行結果
i = 0, j = 0
i = 0, j = 2
i = 0, j = 3
i = 1, j = 0
i = 1, j = 2
i = 1, j = 3
i = 2, j = 0
i = 2, j = 2
i = 2, j = 3
i = 3, j = 0
i = 3, j = 2
i = 3, j = 3
ループ終了