C.W.K.
Stream
Lesson 03 of 05 · published

? 연산자

~11 min · errors, question-mark, propagation, from

Level 0Rust 호기심러
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

? 연산자는 Rust 에러 처리를 즐겁게 만드는 단 하나의 기능이야. 장황한 match-and-bail 패턴을 한 글자로 바꿔.

? 가 하는 일

Result (또는 Option) 뒤에 ? 를 붙여: Ok(v) 면 표현식이 v 로 평가되고 실행이 계속; Err(e) 면 함수가 그 에러와 함께 조기 반환 해. 한 연산자가 'match 하고, Err 면 Err 반환' 춤 전체를 대체해 — 한 줄에 여러 개 체이닝할 수도 있고.

에러를 자동으로 변환해

Traits 트랙으로 이어지는 마법: 전파하는 에러가 함수의 선언된 에러 타입과 다르면, ?From::from 을 불러 변환해. From<LowLevelError> for MyError 를 한 번 구현하면 ? 가 저수준 에러를 네 에러 타입으로 매끄럽게 올려줘. 그게 에러 타입에 From 이 작은 수고 값을 하는 이유야.

? 는 에러에 대한 조기 반환, 공짜 변환 포함. Ok 면 unwrap 하고 계속; Err 면 반환하면서 나가는 길에 From 으로 변환. happy path 가 에러 처리 노이즈 없이 위에서 아래로 읽히고, 실패는 여전히 무시 못 해.

함수가 Result 를 반환해야 해

?Result (또는 Option, 또는 Try 를 구현하는 다른 타입) 를 반환하는 함수에서만 통해. 에러를 반환할 이 필요하거든. main 자체가 Result<(), E> 를 반환할 수 있어서 최상위에서 바로 ? 를 쓸 수 있어.

Code

? 가 match-and-bail 을 대체한다·rust
use std::num::ParseIntError;

// ? 없이: 중첩 match. ? 로: 각각 깔끔한 한 줄.
fn sum_two(a: &str, b: &str) -> Result<i32, ParseIntError> {
    let x = a.trim().parse::<i32>()?; // Ok -> unwrap; Err -> 조기 반환
    let y = b.trim().parse::<i32>()?;
    Ok(x + y)
}

fn main() -> Result<(), ParseIntError> {
    println!("{}", sum_two("20", "22")?); // 42
    // sum_two("x", "1")?; // parse 에러를 main 밖으로 전파할 것
    Ok(())
}

External links

Exercise

sum_two 함수를 중첩 match 버전에서 ? 버전으로 다시 써봐. 둘이 같은 동작으로 컴파일되는지 확인해. 그다음 mainResult<(), ParseIntError> 반환으로 바꾸고 ? 로 에러를 main 밖으로 바로 전파해 — 에러로 종료할 때 프로그램이 뭘 출력해?
Hint
mainErr 를 반환하면 Rust 가 에러의 Debug 표현을 출력하고 0 아닌 코드로 종료해. 그게 fn main() -> Result<(), E> 가 작은 프로그램에 편리한 최상위 패턴인 이유야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.