ここではVB.NETの繰り返し(ループ)ステートメントについて見ていきます。 VB.NETには、
- 初期値・終了値・増分を指定して繰り返すFor-Nextステートメント
- 配列・コレクションの各要素一つずつに対して繰り返すFor-Each-Nextステートメント
- 条件式が成り立っている間繰り返すWhileステートメント
- 条件式が成り立つまで(成り立っている間)繰り返すDo-Loopステートメント
の4つのループ構文が用意されています。 またExit
によってループの中断、Continue
によってループのスキップを行うことができます。
For-Nextステートメント
Forステートメントは繰り返す回数が決まっている場合に使用します。 Forステートメントでは今何回繰り返したかを覚えておくためのカウンタ変数が必要になります。 構文の形式は次の通りです。
For カウンタ変数 = 初期値 To 終了値 [Step 増分]
[ステートメント]
Next [カウンタ変数]
この構文のうち [ ]でくくった部分は省略可能な部分です。
Forステートメントでは、まずカウンタ変数を初期値に指定し、増分で指定した分ずつカウンタ変数の値を増やしていきます。 その度にForから Nextの間に記述されているすべてのステートメントを実行します。 カウンタ変数が終了値に達するか越えた場合、繰り返しが終了します。 このとき増分を省略すると増分は1とされます。
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ステートメントから順に繰り返されていきます。
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ステートメント内で宣言できるようになりました。
' 0 から 9 まで 1 ずつ
For i As Integer = 0 To 9
Console.Write(i)
Next
このようにして宣言したカウンタ変数は、Forステートメント内のみで有効であることに注意してください。 この例の変数iはForステートメントの外から参照することはできません。 カウンタ変数のスコープについてはブロックと変数のスコープも参照してください。
Nextの後ろには対応するForのカウンタ変数を記述することが出来ます。 これは本来省略可能なものですが、多重ループなどの内側の処理が長くなる場合などでは、カウンタ変数を記述することでForステートメントとカウンタ変数の対応が分かりやすくなるようにすることが出来ます。
' 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
For-Each-Nextステートメント
For-Eachステートメントは配列など特定の要素の集まり(コレクション)に対して、そのすべての要素を順番に一つずつ抜き出しながら繰り返す場合に使用します。 For-Eachステートメントでは抜き出した要素を扱うための変数を用意しておく必要があり、その変数の型は当然要素を格納できる型である必要があります。 構文の形式は次の通りです。
For Each 要素変数 In コレクション
[ステートメント]
Next [要素変数]
For-EachステートメントはForステートメントをより簡単にしたようなものなので動作は容易に予想できると思います。 次のコードは配列に含まれるすべての要素を抜き出して表示するコードです。
' 配列
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つずつ要素が抜き出されます。
' 二次元配列
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)からは、ステートメント内で使用できる要素変数をステートメント部で宣言できるようになりました。
' 配列
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で詳しく解説しています。
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ステートメントを参照してください。
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ステートメントを使用することでループを中断することができます。
無限ループ
Do-Loopステートメントでは条件式を省略することができ、これを省略すると無限ループとなります。 Do-Loopステートメントを使えばもっともシンプルに無限ループを記述できます。
' 無限ループ
Do
' 停止するまで 'あ' と表示し続ける
Console.Write("あ")
Loop
C言語で無限ループを記述するのに使われるwhile(1) {...}
をVBで記述する場合は、While-End Whileステートメントが使えます。 条件式が常に真となれば無限ループとなるので、次の例ではTrue
を使っています。
' 無限ループ
While True
' 停止するまで 'あ' と表示し続ける
Console.Write("あ")
End While
もう一つ、C言語で使われる無限ループfor(;;) {...}
をVBで記述する場合はFor-Nextステートメントが使えます。 ただし、C言語のfor文ではループの終了条件を記述するのに対しFor-Nextステートメントではループの終了値を記述するという違いがあります。 そのため、次の例ようにStep 0
を指定して終了値に達することがないようにすることでFor-Nextステートメントで無限ループを記述することが出来ます。
' 無限ループ
For i As Integer = 0 To 1 Step 0
' 停止するまで 'あ' と表示し続ける
Console.Write("あ")
Next
Stepを記述しない代わりに、カウンタ変数の値を元に戻すことで終了値に達しないようにすることでも無限ループを記述出来ます。
' 無限ループ
For i As Integer = 0 To 2
' 停止するまで 'あ' と表示し続ける
Console.Write("あ")
i -= 1 ' カウントアップした分を戻す
Next
無限ループを記述する場合でも、ある条件を満たした場合にループを抜けたいという場合には、Exitステートメントを使用します。
ループステートメントの中断とスキップ
Exitステートメント (ループの中断)
ForやWhileなどのステートメントでは、ループの途中でループから抜けることができます。 その場合にはExitステートメントを使います。 これはCやC#のfor文におけるbreakに相当するものです。 ForループではExit For、WhileループではExit Whileのように使います。
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
Dim i As Integer = 0
' 無限ループ
Do
i += 1
Console.WriteLine(i)
' i が 3 になったらループから抜ける
If i = 3 Then Exit Do
Loop
1 2 3
入れ子になっているループとExitステートメント
入れ子になっている(ネストされた)ループ構造の中でExitステートメントを実行する場合は、Exitで指定したものに対応するループ構文のうち、最も内側にあるものが中断される点に注意が必要です。 次の例では二重のForステートメントの内側でExit 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ステートメントはここで紹介した繰り返し構文の他にも、プロシージャの中断でも使われます。
入れ子になっているループからの脱出
Exitステートメントではもっとも内側にあるExitに対応するループを中断することは出来ますが、Exitステートメントだけでは二重のForループを中断するといったことが出来ません。 入れ子になっているループから脱出する方法にはいくつかありますが、その一つは次のようにフラグと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ステートメントを使ってループの外に脱出する方法です。
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 ループ終了
Continueステートメント (ループのスキップ)
VB.NET 2005 (Visual Studio 2005)からはContinueステートメントが使えるようになりました。 Continueステートメントを使うと、ループの途中で残りの処理をスキップし、ループ処理の先頭に戻ることができます。 これはCやC#のfor文におけるcontinueに相当するものです。 Continueステートメントでスキップした場合、Continue以降の処理は実行されなくなります。 Exitステートメントと同様、ForループではContinue For、WhileループではContinue Whileのように使います。
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 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 ループ終了