ざっくりZig - 繰り返し (while, break, continue)

2024/03/28に公開

繰り返しというのは、何度も同じ処理を行うということです。とはいえ、毎回全く同じ処理を行うのではなく、1回ごとに変数の値を変えながら処理を行うことが多いです。その方法として、ここではwhileを紹介します。

また、繰り返し処理を途中で中断するbreakや、中断しつつ次の繰り返しを行うcontinueも一緒に紹介します。

whileによる繰り返し

whileは条件式の結果がtrueとなる間は{...}内の処理を繰り返し行うことを表します。

while (条件式) {
    // 繰り返し行う処理
}

1.は変数iの値が5より小さい間(i < 5)iの値を表示するという処理をwhileで行います。これは繰り返し処理としてはもっとも基本的なものです。

ポイントは{...}の中でiの値がどのように変化していくかです。この処理の場合、{...}の処理が1回行われるごとにiの値は0~4まで1ずつ増加していきます。これは{...}の処理が5回行われたことを意味します。その結果、iは最初に0が代入されていましたが、繰り返しが終了した後のiの値は5になっています。

1. whileによる繰り返し処理
const std = @import("std");
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 0;

    // 繰り返し処理を行う前のiの値
    try stdout.print("before: i = {}\n\n", .{i});

    // whileによる繰り返し処理
    while (i < 5) {
        try stdout.print("while: i = {}\n", .{i});
        i += 1; // iの値を1増やす
    }

    // 繰り返し処理を行った後のiの値
    try stdout.print("\nafter: i = {}\n", .{i});
}

// 結果
before: i = 0

while: i = 0
while: i = 1
while: i = 2
while: i = 3
while: i = 4

after: i = 5

2.はbreakによりiが1より大きくなった時(2になった時)に繰り返しを中断します。これにより{...}の部分が実行されるのはiの値が0, 1, 2の時までとなります。iの値を1増やす前にbreakが実行されていますので、処理が中断された後もiの値は2のままです。

2. breakによる繰り返しの中断
const std = @import("std");
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 0;

    // 繰り返し処理を行う前のiの値
    try stdout.print("before: i = {}\n\n", .{i});

    // whileによる繰り返し処理
    while (i < 5) {
        try stdout.print("while: i = {}\n", .{i});
        if (i > 1) break; // iの値が1を超えたら中断
        i += 1; // iの値を1増やす
    }

    // 繰り返し処理を行った後のiの値
    try stdout.print("\nafter: i = {}\n", .{i});
}

//結果
before: i = 0

while: i = 0
while: i = 1
while: i = 2    // この後breakにより繰り返しを中断

after: i = 2

3.はiの値が1のとき、その値を3増やして次の繰り返しを行います。continueにより処理を途中で切り上げていますので、その下の i += 1 は実行していません。

3. continueにより次の繰り返しへ
const std = @import("std");
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 0;

    // 繰り返し処理を行う前のiの値
    try stdout.print("before: i = {}\n\n", .{i});

    // whileによる繰り返し処理
    while (i < 5) {
        try stdout.print("while: i = {}\n", .{i});
        if (i == 1) {
            i += 3;
            continue; // iの値を3増やして次の繰り返し
        }
        i += 1; // iの値を1増やす (i == 1のときは実行しない)
    }

    // 繰り返し処理を行った後のiの値
    try stdout.print("\nafter: i = {}\n", .{i});
}

// 結果
before: i = 0

while: i = 0
while: i = 1    // このあと i += 3 を実行
while: i = 4

after: i = 5

4.はi += 1の部分を条件の次に: (i += 1)のように書いています。この部分は繰り返し処理の最後に実行されます。結果は1.と同じです。

4. i += 1 を条件の次に書く場合
const std = @import("std");
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 0;

    // 繰り返し処理を行う前のiの値
    try stdout.print("before: i = {}\n\n", .{i});

    // whileによる繰り返し処理
    while (i < 5) : (i += 1) {
        try stdout.print("while: i = {}\n", .{i});
    }

    // 繰り返し処理を行った後のiの値
    try stdout.print("\nafter: i = {}\n", .{i});
}

// 結果
// 1.と同じ

ただ注意したいのは、continueで次の繰り返しを行う際にもこの部分が実行されることです。そのため: (...)で変数の値を変更しているときは、その値がどのように変化するかを確認するようにしましょう。

なお、: (...)では5.のように{...}で囲まれた複数の処理を実行することもできます。

5. 条件式の次に複数の文を書く
const std = @import("std");
pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    var i: u8 = 0;
    var j: u8 = 1;

    // 繰り返し処理を行う前のiの値
    try stdout.print("before: i = {}\n\n", .{i});

    // whileによる繰り返し処理
    while (i < 5) : ({
        i += 1;
        j += 2;
        try stdout.print("count:  i, j = {}, {}\n", .{ i, j });
    }) {
        try stdout.print("while: i, j = {}, {}\n", .{ i, j });
        if (i == 1) {
            i += 3;
            continue; // iの値を3増やして次の繰り返し
        }
    }

    // 繰り返し処理を行った後のiの値
    try stdout.print("\nafter: i = {}\n", .{i});
}

// 結果
before: i = 0

while: i, j = 0, 1
count: i, j = 1, 3
while: i, j = 1, 3
count: i, j = 5, 5  // continueの後にも実行されている

after: i = 5

まとめ

  • whileは条件式の結果がtrueの間は{...}の処理を繰り返し実行する
  • breakにより繰り返し処理を中断したり、continueにより処理を途中で切り上げて次の繰り返しを行うこともできる
  • 条件式の次に: (i += 1)のような処理を書くこともできる。ただし、continueで次の繰り返し処理を行う際にも実行されるため、変数の値がどう変化するか確認する必要がある
  • : (...)の部分は{...}で囲まれた複数の処理を実行することもできる

繰り返しの応用 (for, while, else, break, continue, オプション, ラベル) >
< 判断と振り分け (if, switch)
ざっくりZig 一覧

Discussion