処理を繰り返すためのwhile
/ for
について説明します。
while
は条件を満たす間、同じ処理を繰り返します。while (条件式) { ... }
が基本構文です。条件式には、ブール型、オプション型、エラー共用体が入ります。条件式がtrue
、null
でない、エラー型でない、間はブロック内の処理を繰り返します。
次のプログラムは、i
が10
より小さい間、i += 1
を実行します。i
は0
で初期化されているため、都合10回ループが繰り返されることになります。while
ループを抜けた直後、i
の値は10
になっています。
examples/ch04-basic-syntax/src/while.zen:4:10
test "while" {
var i: u32 = 0;
while (i < 10) {
i += 1;
}
ok(i == 10);
}
毎ループ繰り返す処理を記述することができます。while (条件式) : (変化式) { ... }
という構文を使います。ブロック ({}
) も式のため、変化式として書くことができます。
次のコードは、以前の例でブロック内に書かれていた処理を変化式として書くように直したものです。
examples/ch04-basic-syntax/src/while.zen:12:16
test "while with continue expression" {
var i: u32 = 0;
while (i < 10) : (i += 1) {}
ok(i == 10);
}
複数の式を変化式内に書きたい場合は、ブロックを使用します。
examples/ch04-basic-syntax/src/while.zen:18:27
test "block as continue expression" {
var i: u32 = 0;
var j: u32 = 0;
while (i < 10 and j < 10) : ({
i += 1;
j += 1;
}) {}
ok(i == 10);
ok(j == 10);
}
continue
以降のブロック内の処理を実行せず、ループの先頭に戻ります。
examples/ch04-basic-syntax/src/while.zen:29:41
test "continue" {
var num_even: u32 = 0;
var i: u32 = 0;
while (i < 10) : (i += 1) {
if (i % 2 == 0) {
num_even += 1;
continue;
}
// `i`が奇数の時のみ、実行される
ok((i % 2) == 1);
}
ok(num_even == 5);
}
i
が偶数の場合、num_even += 1;
が実行された後、continue;
によりループの先頭に戻ります。上のコードでcontinue;
がない場合には、i
が偶数の場合にもok((i % 2) == 1);
が実行されてしまい、テストが失敗します。
continue
でループの先頭に戻った場合も、変化式が実行されることに注意して下さい。
break
を使ってループを途中で終了させることができます。以下のコードでは、whileの条件式ではなく、break;
でループを終了しています。
examples/ch04-basic-syntax/src/while.zen:43:54
test "break in while" {
var i: u32 = 0;
// `i`が10より小さい間ループするwhile
while (i < 10) : (i += 1) {
// `i`が`5`の場合、ループを抜ける
if (i == 5) {
break;
}
}
// `i`は5までしか増えていない
ok(i == 5);
}
Zenではwhileもまた式であるため、値を返すことができます。whileのブロック内で値を返す場合も、break
を使用します。whileのブロック内からbreak
で値を返す場合、whileブロック内でbreak
されなかった場合のためのelse
が必要です。
次のコードは、第一引数で与えたスライス (slice
) 内に、第二引数で与える数値 (number
) が含まれているかどうか、をブール型で返します。number
がslice
に含まれている場合、break true
でtrue
がresult
に格納されます。一方、含まれていない場合は、whileループを抜けて、else false
によりfalse
がresult
に格納されます。
examples/ch04-basic-syntax/src/while.zen:56:65
fn sliceHasNumber(slice: []u32, number: u32) bool {
var i: u32 = 0;
const result = while (i < slice.len) : (i += 1) {
if (slice[i] == number) {
break true;
}
} else false;
return result;
}
上記コードを使う例は以下の通りです。
examples/ch04-basic-syntax/src/while.zen:67:75
test "while expresssion" {
const slice = [_]u32{ 1, 3, 5, 7 };
var result = sliceHasNumber(&slice, 5);
ok(result == true);
result = sliceHasNumber(&slice, 6);
ok(result == false);
}
else
を省略すると、while式の返り値型がvoid
型になるので、コンパイルエラーになります。
fn sliceHasNumber(slice: []u32, number: u32) bool {
var i: u32 = 0;
const result = while (i < slice.len) : (i += 1) {
if (slice[i] == number) {
break true;
}
}; // `else`を省略
return result;
}
error[E02047]: unable to convert 'void' to 'bool'
const result = while (i < slice.len) : (i += 1) {
~
whileループにラベルをつけ、continue
やbreak
時にラベルを参照することができます。これはネストしたループを作成した時に便利です。
2重にネストされたwhileループの例を示します。中のループから外側のループのラベルを参照してcontinue
しています。
examples/ch04-basic-syntax/src/while.zen:77:88
test "labeled while" {
var i: u32 = 0;
outer: while (i < 10) : (i += 1) {
var j: u32 = 0;
while (j < 10) : (j += 1) {
// 中のループに入ると外のループの最初に戻る
continue :outer;
}
// ここには来ない
ok(false);
}
}
次は、break
の例です。
examples/ch04-basic-syntax/src/while.zen:90:101
test "labeled while" {
var i: u32 = 0;
outer: while (i < 10) : (i += 1) {
var j: u32 = 0;
while (j < 10) : (j += 1) {
// 中のループに入ると外のループごと抜ける
break :outer;
}
}
// 外のループも最初の1回しか実行されない
ok(i == 0);
}
if
のように、while
ループでもオプション型を条件式として受け取り、中の値をキャプチャすることができます。もし、オプション型の値を評価した結果がnull
であれば、ループを終了します。ループを終了した時の処理は、else
に記述することができます。
examples/ch04-basic-syntax/src/while.zen:103:114
fn returnNullIfZero(a: u64) ?u64 {
return if (a == 0) null else a;
}
test "optional while" {
var num: u64 = 3;
while (returnNullIfZero(num)) |value| {
num -= 1;
} else {
ok(num == 0);
}
}
if
のように、while
ループでもエラー共用体を条件式として受け取り、中の値をキャプチャすることができます。もし、エラー共用体の値を評価した結果がエラー型であれば、ループを終了します。ループを終了した時には、else
でエラー型の値をキャプチャして、エラー処理しなければなりません。
examples/ch04-basic-syntax/src/while.zen:116:127
fn returnErrorIfZero(a: u64) !u64 {
return if (a == 0) error.IsZero else a;
}
test "error union while" {
var num: u64 = 3;
while (returnErrorIfZero(num)) |value| {
num -= 1;
} else |err| {
ok(err == error.IsZero);
}
}
繰り返しを実現するもう1つの手段はfor
です。for
はスライスまたは配列の要素を繰り返し処理します。基本構文はfor (スライス / 配列) |要素のキャプチャ| { ... }
です。
下記のコードでは、配列items
の要素を順番に処理しています。各配列要素を|value|
でキャプチャしています。
examples/ch04-basic-syntax/src/for.zen:4:12
test "for" {
const items = [_]u32{ 1, 2, 3, 4 };
var sum: u32 = 0;
for (items) |value| {
sum += value;
}
ok(sum == 10);
}
配列要素のインデックスを得たい場合は、|value, i|
と書くと2つ目の識別子i
にインデックスを格納することができます。
examples/ch04-basic-syntax/src/for.zen:14:19
test "get index" {
const items = [_]u32{ 0, 1, 2, 3 };
for (items) |value, i| {
ok(value == i);
}
}
処理するスライス / 配列の要素を更新する場合は、要素への参照をキャプチャします。要素への参照をキャプチャするためには、先頭にアスタリスク (*
) を付けて|*要素のキャプチャ|
とします。
examples/ch04-basic-syntax/src/for.zen:21:30
const equalSlices = std.testing.equalSlices;
test "for reference" {
var items = [_]u32{ 1, 2, 3, 4 };
for (items) |*value| {
// `items`内の値を書き換える
value.* += 1;
}
equalSlices(u32, &[_]u32{ 2, 3, 4, 5 }, &items);
}
Zenのforは式なので、値を返すことができます。while
の時と同様に、break
でブロック内から値を返すことができます。for
のブロック内でbreak
しなかった場合のために、else
で同じ型の値を返します。
examples/ch04-basic-syntax/src/for.zen:32:40
fn sliceHasNumber(slice: []u32, number: u32) bool {
const result = for (slice) |value| {
if (value == number) {
break true;
}
} else false;
return result;
}
while
と同様に、for
ループにもラベルを付けることができます。continue
とbreak
を使った例を、それぞれ示します。
examples/ch04-basic-syntax/src/for.zen:62:79
test "labeled for" {
const array2D = [_][4]u32 {
[_]u32{ 1, 2, 3, 4 },
[_]u32{ 5, 6, 7, 8 },
};
var result: u32 = 0;
outer: for (array2D) |array1D| {
for (array1D) |value| {
// 中の配列の第一要素だけ`result`に加算して外のループに戻る
result += value;
continue :outer;
}
// ここには来ない
ok(false);
}
ok(result == 6);
}
examples/ch04-basic-syntax/src/for.zen:81:96
test "labeled for" {
const array2D = [_][4]u32 {
[_]u32{ 1, 2, 3, 4 },
[_]u32{ 5, 6, 7, 8 },
};
var result: u32 = 0;
outer: for (array2D) |array1D| {
for (array1D) |value| {
// 中の配列の第一要素だけ`result`に加算して外のループを終了する
result += value;
break :outer;
}
}
ok(result == 1);
}
☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2020 connectFree Corporation. All rights reserved. | 特定商取引法に基づく表示
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.