값이 없거나 작업이 실패했을 때 프로그램이 어떻게 처리할지 선택하세요. 입력이 None에서 Err로 바뀌는 과정을 따라가고, 실행을 멈추는 배열 접근을 고쳐 봅니다.
첫 프로그램에서 토파즈를 설치하세요. 예제를 단계별로 배우려면 실패와 리소스부터 시작하세요.
Result로 잘못된 입력 처리하기
다음 코드를 failures-resources.tpz로 저장하세요.
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")그 폴더에서 파일을 검사하고 실행하세요.
topaz check failures-resources.tpz
topaz run failures-resources.tpz두 명령 모두 종료 코드 0으로 끝납니다. 프로그램은 "later"의 오류 메시지를 출력하고 검사를 마칩니다.
input: 25
ready: Build application, 25 minutes
inspection finished
input: later
cannot add task: minutes must be a positive integer
inspection finishedOption은 값이 있으면 Some에 담고, 없으면 None으로 나타냅니다. 여기서 toInt("25")는 Some(25), toInt("later")는 None을 반환합니다.
Result는 성공한 값을 Ok에, 오류 값을 Err에 담습니다. 분해석 함수는 양의 정수를 받습니다. 값이 없거나 0 또는 음수이면 위 메시지를 담은 Err를 반환합니다.
과제만들기의 후위 ?는 Ok에서 정수를 꺼냅니다. Err를 받으면 즉시 그 오류를 과제만들기의 결과로 반환합니다. 마지막 match는 과제나 오류 메시지를 출력합니다. 두 번째 입력을 성공시키려면 "later"를 "10" 같은 양의 정수 문자열로 바꾸세요.
상황에 맞는 표현 선택하기
| 상황 | 사용할 형식 또는 결과 |
|---|---|
| 값이 없을 수 있음 | Some(value) 또는 None을 담는 Option<T> |
외부 데이터의 필드가 null을 허용함 | T | null |
| 호출자에게 결과나 오류 설명이 필요함 | Ok(value) 또는 Err(error)를 담는 Result<T, E> |
| 배열 범위 초과처럼 잘못된 연산으로 실행이 멈춤 | 실행 오류인 fault |
토파즈 API에서 예상되는 값 없음은 Option으로 표현하세요. 다루는 외부 데이터에 null이 들어 있으면 null을 사용합니다.
값에 접근하거나 기본값 쓰기
| 입력 타입 | 표현식 | 결과 |
|---|---|---|
maybeUser: Option<{ name: string }> | maybeUser?.name | Some(name) 또는 None |
| 위와 같은 입력 | maybeUser?.name ?? "guest" | 이름이 있으면 이름, 없으면 "guest" |
configPath: string | null | configPath ?? "default.toml" | 경로가 있으면 경로, null이면 "default.toml" |
?.는 값이 있을 때 필드에 접근하거나 메서드를 호출합니다. 값이 없으면 Option은 None, null 허용 값은 null을 결과로 냅니다. 멤버가 이미 Option을 반환하면 ?.는 그 결과를 Option으로 한 번 감싼 상태로 유지합니다.
??는 선택 값의 한 겹을 벗기며, 좌항이 None이나 null일 때 우항을 평가합니다. 두 연산자 모두 좌항을 한 번 평가합니다. ?.는 접근할 값이 없으면 메서드 인자도 평가하지 않습니다.
target ??= value는 대입 대상이 None이나 null일 때 값을 대입합니다. 대상은 변경 가능해야 합니다. Option<int>에 대입할 값은 Some(42)처럼 쓰세요. 토파즈는 Some을 자동으로 붙이지 않습니다.
일반 값에는 .을 쓰세요. 유니온에 Option<T>와 null이 함께 있으면 멤버에 접근하기 전에 match로 경우를 나누세요.
실행 오류를 찾아 고치기
다음 프로그램은 별도 파일 intentional-fault.tpz로 저장하세요.
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])
| ^^^^^^
이 배열의 인덱스는 0과 1입니다. 2행의 과제들[2]를 과제들[1]로 바꾸고 다시 실행하세요. Build application을 출력하고 종료 코드 0으로 끝납니다.
실행 오류는 None이나 Err를 반환하지 않고 실행을 멈춥니다. ?, ??, ?., concurrent로 이 오류를 잡을 수 없습니다. 잘못된 상수 연산은 실행 전 검사 단계에서 거부될 수 있습니다.
오류 전달과 정리
- 같은 오류 값을 반환할 수 있는 함수나 클로저 안에서
Result뒤에 후위?를 붙이세요. - 토파즈에는
try블록, 예외 처리, 실행 오류 포착, panic 키워드, 자동 재시도가 없습니다. - 내장
assert(...)를 쓰려면test-profile을 명시적으로 선택해야 합니다. - 스코프를 정상적으로 나갈 때 정리하려면
defer를 쓰세요.?로 일찍 반환할 때도 실행합니다. 실행 오류 이후의 정리 동작은 정해져 있지 않습니다.
정리 순서는 Defer와 리소스에서, 실행 오류를 일으키는 다른 연산은 런타임 동작에서 확인하세요.