100 Exercises To Learn Rust - 5.9 error trait 풀기

문제 & 풀이

// TODO: TicketNewError 열거형에 `Debug`, `Display`, `Error` 트레이트를 구현하세요.
// `Display`를 구현할 때, `write!` 매크로를 사용하고 싶을지도 모릅니다.
// `std::fmt` 모듈의 문서는 좋은 예시가 될 것입니다.
//  https://doc.rust-lang.org/std/fmt/index.html#write

#[derive(Debug)]
enum TicketNewError {
    TitleError(String),
    DescriptionError(String),
}

impl std::fmt::Display for TicketNewError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            TicketNewError::TitleError(msg) => write!(f, "{}", msg),
            TicketNewError::DescriptionError(msg) => write!(f, "{}", msg),
        }
    }
}

impl std::error::Error for TicketNewError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}


// TODO: `easy_ticket`은 제목이 잘못되면 TicketNewError enum에 저장된 에러 메시지를 사용하여
// panic을 일으키고, description이 잘못되면 "Description not provided"라는 기본 메시지를 사용하세요.
fn easy_ticket(title: String, description: String, status: Status) -> Ticket {
    match Ticket::new(title.clone(), description, status.clone()) {
        Ok(ticket) => ticket,
        Err(err) => match err {
            TicketNewError::TitleError(msg) => panic!("{}", msg),
            TicketNewError::DescriptionError(_) => {
                Ticket::new(title, "Description not provided".into(), status).unwrap()
            }
        },
    }
}

 

Debug 구현

#[derive(Debug)]
enum TicketNewError {
    TitleError(String),
    DescriptionError(String),
}

 

Debug는 derive로 자동 구현할 수 있다.

 

Display 구현

impl std::fmt::Display for TicketNewError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            TicketNewError::TitleError(msg) => write!(f, "{}", msg),
            TicketNewError::DescriptionError(msg) => write!(f, "{}", msg),
        }
    }
}

 

Displaydoc를 참고해서 작성할 수 있다.

 

fmt 함수의 내부에서 match를 이용해 TicketNewError의 모든 배리언트에 대한 출력 메시지를 write! 매크로를 이용해 정의한다.

 

Error 구현

impl std::error::Error for TicketNewError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}

 

공식 솔루션에는 impl std::error::Error for TicketNewError {}으로 아예 비워져 있다.

 

assert_impl_one!(TicketNewError: std::error::Error) 테스트를 통과하기 위해서 작성해야 하지만, 별 역할은 하지 않는다.

 

? 연산자를 사용하여 에러 전파를 간편하게 처리하고 싶을 때나,
에러 체이닝(source())을 통해 원래 에러의 원인을 유지해야 할 때 에러 트레이트를 이용하면 편리하다.