기본 사용법
Zero의 if는 다른 C 계열 언어의 if와 거의 비슷하게 생겼는데, 한 가지 두드러진 제약이 있습니다. 조건이 bool이어야 한다는 것입니다.
조건 value == 42는 두 i32 사이의 ==가 bool을 반환하기 때문에 bool입니다. 두 분기는 각각 문장 블록을 담고 있어요. 한쪽 분기를 생략하는 건 어느 정도 가능합니다 — else는 선택 사항이거든요 — 하지만 둘 다 있을 때는 모두 { ... } 블록이어야 합니다.
bool 요구 사항
if value { ... }라고 적고 0, "", null을 거짓으로 다루는 언어가 있죠. Zero는 그러지 않습니다. 조건은 실제 bool이어야 합니다.
let count = 0
if count { // 컴파일 에러: bool을 기대했는데 i32가 옴
// ...
}
if count == 0 { // OK
check world.out.write("nothing to do\n")
}
이유는 언어 전체를 관통하는 그 원칙과 같아요. 명시적인 것이 암묵적인 것을 이깁니다. 두 번째 형태를 읽는 에이전트는 무엇이 검사되고 있는지 정확히 압니다. 첫 번째 형태는 참/거짓 규칙을 암묵적으로 남기고, 그것은 언어마다 다릅니다. Zero는 거기서 빠집니다.
Else와 Else-If
조건이 거짓일 때 else 절이 실행됩니다.
else if로 조건을 체인합니다.
if value < 0 {
check world.out.write("negative\n")
} else if value == 0 {
check world.out.write("zero\n")
} else {
check world.out.write("positive\n")
}
else if는 사실 중괄호를 생략한 else { if ... }입니다. 의미는 같고, 들여쓰기만 줄어드는 셈이죠. 마지막 else는 선택입니다.
조건의 출처
조건은 bool로 평가되는 어떤 것이든 될 수 있습니다.
bool바인딩:if ok { ... }.- 비교:
if value == 42 { ... },if x < y { ... }. - 논리 결합:
if a && b { ... },if pair.left == 1_u8 && pair.right == 2_u8 { ... }. bool을 반환하는 함수 호출:if isReady(world) { ... }.
언어 예제에 나오는 실제 코드 한 조각입니다.
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
if pair.left == 1_u8 && pair.right == 2_u8 {
check world.out.write("type alias ok\n")
} else {
check world.out.write("type alias broke\n")
}
&&는 예상한 대로 단락 평가를 합니다. 왼쪽이 false면 오른쪽은 평가되지 않아요. ||도 마찬가지입니다.
match로 갈 때
if/else if 체인은 두 갈래나 세 갈래 결정에 잘 어울립니다. 특히 조건들이 구조를 공유하지 않을 때요. 하지만 합 타입의 변종 — choice나 enum — 으로 분기한다면 match가 맞는 도구입니다.
비교해 봅시다.
// match — 망라적이고 컴파일러가 검사
match result {
.ok => value { check world.out.write("ok\n") }
.err => message { check world.out.write("err\n") }
}
vs.
// 합 타입을 if/else로 — 장황하고 틀리기 쉬움
if result.isOk() {
let value = result.unwrap()
check world.out.write("ok\n")
} else {
check world.out.write("err\n")
}
match 형태는 변종 분석을 명시적으로 만들고, 나중에 변종이 추가됐을 때 처리를 잊으면 컴파일러가 그 사실을 알려줍니다. if 형태는 ok가 아닌 어떤 것도 (생각조차 해본 적 없는 새 변종까지) 조용히 else 분기로 흘려 보냅니다.
경험칙: 불리언에는 if, 변종에는 match.
스타일 노트
사람과 에이전트 모두에게 코드를 읽기 쉽게 만드는 작은 관행 몇 가지입니다.
- 본문은 늘 중괄호로 감싸세요. 한 줄짜리 본문도
{ ... }안에 두세요. 중괄호 없는 단문 형태가 없는 건 의도된 거예요. 들여쓰기를 일관되게 유지하고, C 계열에서 흔히 나는 버그 원인을 없앱니다. - 가장 흔한 분기를 먼저 두세요. 읽는 사람(과 에이전트)은 위에서 아래로 훑습니다.
- 동등한 조건이라면 긍정 조건을 선호하세요. 다른 게 같다면
if !notReady보다if isReady가 따라가기 쉽습니다.
다음 글: while 루프
조건문은 무엇을 할지 정하고, 루프는 몇 번 할지 정합니다. 다음 문서에서는 Zero가 초기 단계에 함께 출시한 루프 구조, while 루프를 다룹니다.
자주 묻는 질문
Zero의 if 문은 어떻게 동작하나요?
if 조건 { ... } 형태를 쓰고, 선택적으로 else { ... } 절을 붙일 수 있습니다. 조건은 bool이어야 해요. Zero는 정수, 문자열, 그 외의 값을 불리언으로 강제 변환하지 않습니다. 예: if value == 42 { check world.out.write("yes\n") } else { check world.out.write("no\n") }.
Zero에 삼항 연산자가 있나요?
Zero는 표면적을 의도적으로 작게 유지하고, 별도의 condition ? a : b 삼항 연산자 대신 if/else 블록을 씁니다. 공식 예제도 짧은 케이스에서조차 명시적 분기를 선호하고요. 언어가 if-as-expression을 지원한다면, 두 번째 문법을 새로 도입하기보다는 그 방향으로 갈 가능성이 큽니다.
Zero에서 if/else if를 체인으로 연결할 수 있나요?
네. 분기 사이에 else if를 적어 체인을 만들면 됩니다: if a { ... } else if b { ... } else { ... }. choice나 enum을 좀 더 정교하게 분기하려면 match 쪽으로 가세요. 더 망라적이고, 컴파일러가 모든 변종을 처리했는지 검사해 줍니다.
Zero는 왜 값을 bool로 강제 변환하지 않나요?
Zero의 설계 철학은 '모든 것은 명시적이다'입니다. 0, "", null 같은 값을 false로 다루는 암묵적 참/거짓 강제 변환은 흔한 버그의 원인이고, 에이전트가 정확하게 추론하기도 어렵습니다. 실제 bool을 요구하면 분기 결정이 소스에 드러나고, 기계적으로도 검증하기 쉬워집니다.
if/else 대신 match를 써야 할 때는 언제인가요?
choice나 enum의 변종을 기준으로 분기하고 있다면 match를 쓰세요. 컴파일러가 모든 경우를 다뤘는지 검증해 주는데, if/else if 체인은 그걸 못 합니다. 동등 비교, 비교 연산, 짧은 두 갈래 분기 같은 단순한 불리언 조건이라면 if/else가 어울립니다.