트랙
/
Cairo
Cairo
/
학습 과정
/
오류 처리
오류

오류 처리 에서 Cairo

1개의 연습 문제

오류 처리 소개

Cairo는 문제를 해결하고 오류를 관리할 수 있는 오류 처리 기법을 제공해요. 덕분에 코드를 실행하는 동안 매끄럽게 돌아가도록 만들 수 있어요.

Cairo에는 두 가지 종류의 오류가 있어요:

  • panic으로 인한 복구할 수 없는 오류: 이런 오류는 프로그램을 즉시 종료해요.
  • Result로 처리하는 복구 가능한 오류: 이런 오류는 실행 중에 처리할 수 있어요.

panic으로 인한 복구할 수 없는 오류

Cairo에서는 프로그램을 실행하는 도중에 예상치 못한 문제가 생겨서 "패닉"이라는 런타임 오류가 발생할 수 있어요. 패닉이 발생하면 프로그램 실행이 멈춰요. 계속 진행해도 아무 의미가 없는 상황에서는 이런 동작이 도움이 돼요. 패닉은 코드가 스스로 패닉을 일으키는 동작(예를 들어 배열의 범위를 벗어난 곳에 접근하는 경우) 때문에 의도치 않게 발생할 수도 있고, panic 함수를 호출해서 의도적으로 발생시킬 수도 있어요.

fn main() {
    let data = array![1, 2];

    if true {
        panic(data);
    }
    println!("This line will not be reached.");
}

이 예제를 실행하면 콘솔에 다음이 출력돼요:

Run panicked with [1, 2, ].

panic!이라는 특별한 매크로도 있어요. 이 매크로를 쓰면 ByteArray를 오류 메시지로 사용할 수 있어요.

panic!("The error for the panic! Error message is not limited to 31 characters anymore");

assert! 매크로

assert! 매크로는 코드에서 특정 조건을 강제하는 데 유용한 도구예요. assert!의 조건이 false로 평가되면, 프로그램은 ByteArray 오류 메시지와 함께 패닉을 일으켜요. 개발 중에 가정을 확인하고 값이 특정 기준을 만족하는지 검증할 때 자주 사용해요.

예를 들면 다음과 같아요:

fn main() {
    let x = 5;
    assert!(x > 0, "x must be greater than zero");
}

x가 0보다 크지 않으면 프로그램은 "x must be greater than zero" 메시지와 함께 패닉을 일으켜요. assert!를 사용하면 오류 처리 코드를 직접 작성하지 않고도 불변식과 사전 조건을 확인할 수 있어요.

nopanic 표기

Cairo의 nopanic 표기는 함수가 절대 패닉을 일으키지 않는다는 것을 나타내요.

fn function_never_panic() -> felt252 nopanic {
    108
}

nopanic 함수는 nopanic으로 표시된 함수에서만 호출할 수 있어요.

panic_with 어트리뷰트

Cairo의 panic_with 어트리뷰트는 Option이나 Result를 반환하는 함수를 표시할 때 사용해요. 그러면 어트리뷰트를 붙인 함수의 래퍼가 만들어지는데, 이 래퍼는 원래 함수가 Option::None이나 Result::Err를 반환하면 패닉을 일으켜요.

#[panic_with('value is 0', wrap_not_zero)]
fn check_not_zero(value: u128) -> Option<u128> {
    if value == 0 {
        Option::None
    } else {
        Option::Some(value)
    }
}

fn main() {
    check_not_zero(0); // -> returns Option::None
    wrap_not_zero(0);  // -> panics with 'value is 0'
}

Result로 처리하는 복구 가능한 오류

Result 열거형을 사용하면 오류를 매끄럽게 처리할 수 있어요. 프로그램이 멈추거나 정의되지 않은 동작을 일으키는 대신, 피드백을 돌려줘요.

enum Result<T, E> {
    Ok: T,
    Err: E,
}

이 열거형으로 0으로 나누는 상황을 처리하는 예제를 살펴봐요:

fn divide(a: u32, b: u32) -> Result<u32, ByteArray> {
    if b == 0 {
        return Result::Err("Error: Division by zero"); // Return an error if division by zero is attempted
    }
    Result::Ok(a / b)
}

fn main() {
    // Test with division by zero
    match divide(10, 0) {
        Result::Ok(result) => println!("Division successful: {}", result),
        Result::Err(e) => println!("{}", e),
    }
}

? 연산자

? 연산자는 오류 처리를 간결하고 암묵적으로 해줘요. 발생할 수 있는 오류를 호출한 함수가 처리하도록 넘겨줘요. Result나 Option 타입에 ? 연산자를 사용하면 다음과 같이 동작해요:

  • 값이 Result::Ok(x)나 Option::Some(x)이면 안쪽 값 x를 그대로 반환해요.
  • 값이 Result::Err(e)나 Option::None이면 오류나 None을 전파하면서 함수에서 즉시 빠져나와요.
fn parse_u8(s: felt252) -> Result<u8, felt252> {
    match s.try_into() {
        Option::Some(value) => Result::Ok(value),
        Option::None => Result::Err('Invalid integer'),
    }
}

fn do_something_with_parse_u8(input: felt252) -> Result<u8, felt252> {
    let input_to_u8: u8 = parse_u8(input)?;
    // DO SOMETHING
    let res = input_to_u8 - 1;
    Result::Ok(res)
}

fn main() {
    let number: felt252 = 258;
    match do_something_with_parse_u8(number) {
        Result::Ok(value) => println!("Result: {}", value),
        Result::Err(e) => println!("Error: {}", e),
    }
}
GitHub에서 편집 링크가 새 창이나 탭에서 열려요

오류 처리 배우기

연습이 잠겨 있어요

오류 처리 개념을 연습하려면 연습 문제 1개를 더 잠금 해제해요