데이터와 제어

패턴과 제어 흐름

상황별 if, match, for 구문의 선택 기준과 패턴을 활용한 데이터 검사 및 추출 방법.

단일 조건의 참·거짓을 평가할 때는 if를 사용합니다. 값의 구조나 타입에 따라 결과를 선택할 때는 match를 사용합니다. 각 요소에 동일한 작업을 반복할 때는 for를 사용합니다. matchfor 내부의 패턴은 데이터를 검사하는 동시에 필요한 요소에 이름을 바인딩합니다.

예제 실행하기

다음 코드를 data-control.tpz로 저장합니다.

TOPAZ
record 학습과제 {
    제목: string,
: int,
    완료: bool = false,
}

function 속도(과제: 학습과제) -> string {
    if 과제.완료 {
        return "done"
    }
    match 과제. {
        case 1..15 => "quick"
        case 16..30 => "focused"
        case _ => "deep"
    }
}

let 과제들: Array<학습과제> = [
    학습과제 { 제목: "Run first program", : 10, 완료: true },
    학습과제 { 제목: "Build application", : 25 },
]
let mut 남음 = 0
for 과제 in 과제들 {
    if !과제.완료 {
        남음 = 남음 + 과제.
    }
    print("{과제.제목}: {속도(과제)}")
}
print("remaining: {남음} minutes")

먼저 검사한 뒤 실행합니다.

BASH
topaz check data-control.tpz
topaz run data-control.tpz

결과는 배열의 순서를 따릅니다.

출력
Run first program: done
Build application: focused
remaining: 25 minutes

코드가 내리는 세 가지 결정

반복문은 배열의 각 항목을 task라는 이름에 바인딩합니다. 안쪽의 if는 "이 작업이 미완료 상태인가?"라는 단일 참·거짓 조건만 판단합니다. 여러 경우로 분기하거나 값의 내부 구조를 추출할 필요가 없습니다.

양쪽 결과가 모두 필요하다면 if condition { ... } else { ... } 구문을 사용합니다. 두 분기가 서로 호환되는 값을 반환할 경우 if 구문 전체가 표현식의 평가 결과가 됩니다.

속도 함수는 완료된 과제를 if로 먼저 처리합니다. 이어지는 match과제.분을 한 번 평가한 뒤, 상단부터 case를 순차적으로 검사합니다. 1..1516..30은 범위 패턴에 해당합니다. 마지막 _는 나머지 정수를 모두 받아 처리하므로 모든 입력값에 대한 결과가 반환됩니다.

선택알맞은 상황만들어지는 결과
if단일 조건으로 분기할 때각 분기가 호환되는 값을 내면 해당 값, 그렇지 않으면 부수 효과만 수행하는 문장
match값에 의미 있는 구조나 타입이 여러 가지일 때선택된 분기의 반환값 및 해당 분기 내에서 활용할 수 있는 패턴 바인딩
for정해진 순서로 모든 요소를 순회할 때문장으로 사용 시 부수 효과 수행, 식으로 사용 시 본문 평가 결과를 모은 Array

패턴은 검사와 바인딩을 함께 한다

리터럴 패턴과 범위 패턴은 일치 여부를 검사합니다. 과제처럼 식별자만 지정한 패턴은 일치하는 값을 해당 이름에 바인딩합니다. Some(값)이나 Err(메시지) 같은 생성자 패턴은 OptionResult 내부의 값을 추출합니다. 레코드 패턴은 명시한 필드만 선택하여 추출합니다.

배열 패턴에서 남은 요소를 표시할 때는 ... 대신 ..를 사용합니다. case [head, ..tail] =>는 첫 항목을 head에 바인딩하고, 남은 항목은 Array 타입인 tail에 바인딩합니다. 나머지 값을 사용할 필요가 없을 때는 _로 처리합니다.

if let 패턴 = 값 { ... }은 매칭 성공 케이스 하나만 다룰 때 유용하며, 실패 경로는 필요한 경우에만 구성합니다. while let은 패턴이 더 이상 일치하지 않을 때까지 동일한 검사를 반복합니다. 두 구문이 생성한 바인딩은 변경할 수 없으며, 매칭 성공 블록 내부에서만 유효합니다.

흔한 실수

패턴 표현식에 [head, ...tail]을 사용해서는 안 됩니다. ...는 배열이나 함수 호출에서 전개 연산자로 사용됩니다. 리스트 패턴에서 나머지 요소를 지정하는 올바른 표기는 [head, ..tail]입니다.

열거형은 인스턴스를 생성할 때와 패턴으로 검사할 때의 표기가 다릅니다. 값 생성 시에는 상태.일시정지("review")처럼 열거형 이름을 포함합니다. 패턴 매칭에서는 case 일시정지(이유) =>처럼 배리언트 이름만 명시합니다.

선택에 영향을 주는 정확한 동작

  • 값을 반환하는 ifmatch의 분기 결과는 서로 호환되어야 합니다.
  • 닫힌 열거형을 match하면 모든 배리언트를 다루는지 검증합니다. 가드가 결합된 분기는 완전성 판단 대상에서 제외됩니다.
  • 검증기가 모든 경우를 처리했다고 입증하지 못하면 _ 분기를 직접 작성합니다.
  • 패턴은 좌측에서 우측 방향으로 평가합니다. 불일치한 대안에서 생성된 바인딩은 다음 대안으로 전달되지 않습니다.
  • 컬렉션 컴프리헨션에서 실패 가능 패턴이 일치하지 않으면 해당 항목을 건너뛰지 않고 런타임 오류가 발생합니다. 항목을 거르려면 if 절을 직접 작성합니다.
  • Array·정수 범위·Set·map.keys에는 정해진 순회 순서가 있습니다. 문자열은 직접 순회하지 않습니다.
  • while과 문장 위치의 for는 값을 생성하지 않습니다. 식으로 작성한 for는 본문 평가 결과를 소스 순서대로 수집합니다.

사용자 정의 패턴·반복자·생성기·실행 오류를 처리하는 제어 구조·while이나 for에 지정하는 레이블은 현재 언어 범위에 포함되지 않습니다.

학습 과정의 데이터와 제어 예제에서 이어서 살펴볼 수 있습니다. 패턴이 여는 데이터 구조는 레코드와 명목 데이터를 참고하세요. 순회와 필터링은 컬렉션과 컴프리헨션을 참고하세요.