옵셔널과 함께 쓰는 while
옵셔널과 함께 쓰는 while (while with Optionals)
while 루프도 if 표현식처럼 옵셔널을 조건으로 받아 그 값을 잡아낼(capture) 수 있어요. 조건이 null을 만나게 되면 루프는 거기서 종료됩니다.
본문
옵셔널을 조건으로 쓰는 while은 간단해요. while 표현식에 |x| 구문이 붙어 있으면, 그 while의 조건은 반드시 **옵셔널 타입(Optional Type)**이어야 합니다. 조건이 null이 아니면 안에 담긴 값이 |value|로 묶여 루프 본문으로 들어오고, null이 되면 루프가 빠져나가죠.
옵셔널 순회에서는 else 분기도 쓸 수 있어요. 이 경우 else 블록은 처음으로 null을 만난 시점에 실행됩니다.
const expectEqual = @import("std").testing.expectEqual;
test "while null capture" {
var sum1: u32 = 0;
numbers_left = 3;
while (eventuallyNullSequence()) |value| {
sum1 += value;
}
try expectEqual(3, sum1);
// null capture with an else block
var sum2: u32 = 0;
numbers_left = 3;
while (eventuallyNullSequence()) |value| {
sum2 += value;
} else {
try expectEqual(3, sum2);
}
// null capture with a continue expression
var i: u32 = 0;
var sum3: u32 = 0;
numbers_left = 3;
while (eventuallyNullSequence()) |value| : (i += 1) {
sum3 += value;
}
try expectEqual(3, i);
}
var numbers_left: u32 = undefined;
fn eventuallyNullSequence() ?u32 {
return if (numbers_left == 0) null else blk: {
numbers_left -= 1;
break :blk numbers_left;
};
}
$ zig test test_while_null_capture.zig
1/1 test_while_null_capture.test.while null capture...OK
All 1 tests passed.
예제에서 eventuallyNullSequence()는 호출될 때마다 numbers_left를 하나씩 줄이며 그 값을 반환하다가, numbers_left가 0이 되면 null을 돌려줘요. 그래서 세 테스트 모두 처음 3번은 값이 잡히고 4번째 호출에서 루프가 끝나게 됩니다.
- 첫 번째는
while에else없이 순수하게|value|캡처만 쓰는 기본 형태예요. 3번 반복하며sum1이3이 되고, 다음null에서 루프가 나가요. - 두 번째는
else블록을 붙여서,null을 만난 순간(즉 값이 더 이상 없을 때)sum2가3인지 확인합니다. - 세 번째는 continue 표현식을 결합한 모습이에요.
: (i += 1)덕분에 루프가 반복될 때마다 카운터i가 올라가고,null에서 종료된 뒤에도i가3으로 유지되는 걸 검증해요.