토파즈 배우기

실패와 리소스

예상되는 입력 오류를 Option, Result 및 후위 ? 연산자로 다룹니다. defer로 정리를 보장하고 의도적인 fault 발생 사례를 살펴봅니다.

학습 결과: 예상되는 값의 부재와 복구 가능한 실패를 값으로 표현하는 방법을 익힙니다. 스코프가 종료될 때의 리소스 정리를 처리하며, 이들을 런타임 계약 위반과 구분합니다.

선행 학습: 데이터와 제어 학습을 마쳐야 합니다. 값이 if, match, for 구문을 통과하는 제어 흐름을 따라갈 수 있어야 합니다.

잘못된 입력을 예상한 결과로 만들기

failures-resources.tpz 파일을 만드세요.

TOPAZ
record 학습과제 {
    제목: string,
: int,
}

function 분해석(텍스트: string) -> Result<int, string> {
    match toInt(텍스트) {
        case Some() if > 0 => Ok()
        case _ => Err("minutes must be a positive integer")
    }
}

function 과제만들기(제목: string, 분문자열: string) -> Result<학습과제, string> {
    let = 분해석(분문자열)?
    Ok(학습과제 { 제목: 제목, :  })
}

function 검사(분문자열: string) -> () {
    print("input: {분문자열}")
    defer { print("inspection finished") }
    match 과제만들기("Build application", 분문자열) {
        case Ok(과제) => print("ready: {과제.제목}, {과제.} minutes")
        case Err(메시지) => print("cannot add task: {메시지}")
    }
}

검사("25")
검사("later")

검사하고 실행하세요.

BASH
topaz check failures-resources.tpz
topaz run failures-resources.tpz

유효하지 않은 문자열도 데이터로 처리되므로 프로세스가 정상적으로 종료됩니다.

출력
input: 25
ready: Build application, 25 minutes
inspection finished
input: later
cannot add task: minutes must be a positive integer
inspection finished

toInt 함수는 Option을 반환합니다. Some(값)은 정수 값이 존재한다는 의미이고, 나머지 경우는 값이 없음을 나타냅니다. 분해석 함수는 값이 없는 경우와 0 이하인 입력을 에러 메시지가 포함된 Result로 변환합니다.

과제만들기 함수도 Result를 반환합니다. 후위 ? 연산자는 Ok 내부의 값을 추출합니다. Err인 경우 해당 에러 값을 호환되는 현재 함수의 반환값으로 즉시 전달합니다. 따라서 유효하지 않은 작업은 생성되지 않습니다. 점검 함수는 두 가지 반환 결과를 모두 명시적으로 처리합니다.

defer 구문은 검사를 시작한 스코프에 속합니다. 성공한 입력과 실패한 입력은 서로 다른 제어 흐름을 거치지만, 두 경우 모두 마지막에 정리 문구가 출력됩니다. 실제 리소스를 소유하는 함수에서도 필수적인 정리 작업은 이처럼 소유 스코프에 둡니다.

깨진 계약 살펴보기

이제 intentional-fault.tpz 파일을 만드세요.

TOPAZ
let 과제들 = ["Run first program", "Build application"]
print(과제들[2])

topaz run intentional-fault.tpz 명령을 실행하면 0이 아닌 종료 코드로 종료됩니다.

출력
error[TPZ4001]: index 2 is out of bounds for an array of length 2
 --> intentional-fault.tpz:2:7
  |
2 | print(과제들[2])
  |       ^^^^^^

이것은 복구 대상인 Err가 아니라 fault입니다. 프로그램이 배열 경계 계약을 위반했기 때문입니다. 진단 도구는 임의의 값을 생성하지 않고 위반된 계약과 소스 코드 위치를 알립니다.

선택: 값 부재, 복구, 계약 위반

값이 없는 상태가 정상적인 결과라면 Option을 쓰세요. 호출자가 의미 있게 대응할 수 있는 오류에는 Result를 쓰세요. 호환되는 다른 Result로 전달할 때 ?를 씁니다. 계약 위반 상황에는 fault가 적합합니다. 이러한 선택과 별개로 스코프를 빠져나갈 때 리소스를 해제해야 하는 경우 defer를 씁니다.

직접 해보기

정상 작동하는 프로그램에 점검("0")를 추가하세요. 어느 갈래가 실행될까요? 지연 실행되는 정리 문구도 함께 나타날까요?

정답 보기

0은 가드 조건을 통과하지 못하므로 cannot add task: minutes must be a positive integer가 출력됩니다. 점검 스코프를 나갈 때 defer가 실행됩니다. 따라서 다음 줄에는 여전히 inspection finished가 나타납니다.

다음 단계로 넘어갈 준비

잘못된 문자열이 Err가 되는 이유, 과제만들기 안에서 ? 연산자가 작동하는 이유, 정리 문구가 두 번 나타나는 이유, 범위를 벗어난 접근이 예상된 입력이 아니라 fault인 이유를 설명할 수 있다면 준비된 것입니다.

정확한 규칙은 Null·Option·결과·faultDefer와 리소스에서 확인하세요. 첫 애플리케이션으로 계속 진행하세요.