rokdocs
v0.1

3.12. match 표현식

match 는 값을 여러 패턴에 비교한 다음, 처음으로 매칭되는 가지를 평가하는 표현식입니다.

3.12.1. 형태

match_expr  ::= "match" expr "{" match_arm ("," match_arm)* ","? "}"
match_arm   ::= pattern ("if" expr)? "=>" expr
match expr {
    패턴1 => 식1,
    패턴2 => 식2,
    ...
    패턴N => 식N,
}

match 표현식은 match 키워드와 피검사 식, 그리고 { ... } 본체로 구성됩니다. 피검사 식의 최상위에는 struct 리터럴을 둘 수 없습니다 (3.10.3). 본체에는 0 개 이상의 가지 (arm) 가 콤마로 구분되어 등장하며, 각 가지는 패턴과 => 토큰 (구두점과 연산자 토큰), 그리고 식으로 이루어집니다. 마지막에 후행 콤마를 두는 것도 허용됩니다.

3.12.2. 가지의 본체

match v {
    1 => "one",
    2 => "two",
    _ => "other",
}

=> 뒤에는 단일 식이 오는 형태입니다. 식이 블록 표현식 이라면 여러 문장을 자연스럽게 둘 수 있습니다.

match v {                        // v: i32 | none
    n: i32 => {
        let x = n * 2;
        x + 1
    },
    none => 0,
}

블록 가지의 마지막 식 값이 곧 그 가지의 결과가 됩니다.

3.12.3. 매칭 순서

가지는 위에서 아래로 검사되며, 처음으로 매칭되는 가지가 평가됩니다. 그 가지의 식 값이 match 표현식 전체의 결과가 됩니다.

3.12.4. 분기 결과 타입

표현식 개요 의 분기 결과 규칙에 따라, 모든 가지 결과 식이 같은 타입이면 match 식의 결과 타입은 그 타입이 됩니다. 가지 타입이 서로 다르면 받는 쪽에 명시된 타입이 있어야 하며, 합 타입을 자동으로 추론하지는 않습니다. 받는 슬롯의 타입은 변수 선언 의 규칙을 따릅니다.

// 슬롯에 타입 명시 없음 → 식 결과 타입으로 추론
let x = match v {
    1 => "one",
    _ => "other",
};                      // 식 결과 str, 슬롯 x: str

let y = match v {
    1 => 1i32,
    _ => "other",
};                      // ERROR: 가지 타입 불일치 - 타입 명시 필요

// 슬롯에 합 타입 명시 → 항 일치 검사
let w: i32 | str = match v {
    1 => 1i32,
    _ => "other",
};                      // OK

// 슬롯에 단일 타입 명시 → 식 결과가 그 타입이어야
let z: i32 = match v {
    1 => 1i32,
    _ => "other",
};                      // ERROR: str 가지가 i32 에 안 맞음

3.12.5. 완전성 검사 (exhaustiveness)

가지의 패턴 집합은 피검사 식이 가질 수 있는 모든 값을 덮어야 합니다. 그렇지 않으면 컴파일 에러가 발생합니다.

let x: bool = ...;
match x {
    true => 1,
    // ERROR: false 가 빠짐
}

검사 규칙은 다음과 같습니다. 닫힌 합 타입 (A | B) 의 모든 항을 덮으면 완전한 것으로 간주됩니다. enum 의 경우에는 모든 변형을 덮으면 완전해집니다. bool 은 true 와 false 를 모두 덮으면 완전합니다. 정수, char, 문자열, 부동소수의 리터럴과 범위 패턴은 열린 집합으로 취급합니다. 범위들이 타입의 모든 값을 덮더라도 (0..=255 로 u8 전체) 완전한 것으로 보지 않으므로, 와일드카드 (_) 또는 식별자 패턴 (x) 같은 catch-all 가지가 반드시 필요합니다. 완전하지 않다는 에러는 빠진 값 하나를 예로 듭니다 (예: false).

any 슬롯 의 동적 슬롯에 대한 매칭은 어떤 타입이 들어올지 컴파일러가 알 수 없으므로, 항상 catch-all 가지가 필요합니다.

3.12.6. 도달 불가능 가지

매칭 순서상 절대 도달할 수 없는 가지는 컴파일 에러입니다 (경고가 아님). 정수와 char 의 리터럴 / 범위 패턴은 구간으로 비교하므로, 앞 가지들의 구간이 이미 덮은 범위도 도달 불가능입니다 (0..=9 뒤의 3..=5). 범위가 완전성을 만들지는 않습니다 (3.12.5).

match v {
    _ => 0,
    1 => 1,         // ERROR: 위의 _ 가 항상 매칭
}

3.12.7. or 패턴

패턴 의 or 패턴 (|) 을 사용하면 같은 본체를 갖는 여러 패턴을 하나로 묶을 수 있습니다.

match v {
    1 | 2 | 3 => "small",
    4 | 5 | 6 => "medium",
    _         => "large",
}

3.12.8. 가드

패턴 의 가드 (if 조건) 를 가지에 부착할 수도 있습니다.

match (x, y) {
    (a, b) if a == b => "equal",
    (a, b) if a > b  => "first bigger",
    _                => "second bigger",
}

가드가 있는 가지는 완전성 검사에서 catch-all 로 인정되지 않습니다. 가드가 false 가 될 가능성이 있기 때문입니다. 따라서 가드가 붙은 가지만으로는 완전성이 보장되지 않습니다.

let x: bool = ...;
match x {
    a if a == true  => 1,
    a if a == false => 2,
    // ERROR: 가드 가지만으로는 완전성이 보장되지 않음, _ 필요
}

3.12.9. 매칭 결과의 좁히기

타입 패턴이나 enum 패턴이 매칭한 가지 안에서는, 컴파일러가 피검사 식의 타입을 좁혀줍니다.

let v: i32 | str = ...;
match v {
    n: i32 => use_int(n),       // 이 가지에서 n: i32, 정적 디스패치 가능
    s: str => use_str(s),
}

이 좁히기는 any 슬롯 과 합 타입 의 좁히기와 동일한 메커니즘으로 동작합니다.

3.12.10. 평가 순서

match 의 평가는 다음 순서로 진행됩니다.

  1. 피검사 식 평가 (한 번만).
  2. 가지를 위에서 아래로 검사.
  3. 처음 매칭되는 가지의 식 평가.

피검사 식에 부작용이 있다면 그 부작용은 단 한 번만 발생합니다. 또한 가드가 있는 가지의 가드는 그 가지에 도달했을 때에만 평가됩니다.

3.12.11. 매칭 식 자체의 결과

match 표현식 자체의 결과는 위 분기 결과 규칙을 따릅니다 (가지가 모두 같은 타입이면 그 타입이고, 다르면 받는 쪽에 명시된 타입이 있어야 합니다).

피검사 식이 divergent 인 경우 (예: match return 0 { ... }) 에는 match 도 divergent 가 됩니다.

3.12.12. divergent 가지

가지의 식이 블록 표현식 의 divergent 형태 (return, break, throw 등) 라면, 그 가지는 분기 결과 타입 검사에서 임의의 타입과 호환되는 것으로 처리됩니다.

let x: i32 = match v {           // v: i32 | none
    n: i32  => n,
    none    => return 0,         // divergent, i32 자리에서 OK
};

GitHub에서 이 페이지 고치기