資訊技術 - Computer Science

[Rustlings] errors6.rs

主要是要練習如何撰寫及應用 error conversion。

整個程式是要實作一個新的型別 PositiveNonzeroInteger,意即「正整數」;0 或負整數都不是合法的。這個正整數要從字串 parsing 而來。如果 parsing 時就出問題,要把 parse() 的 error 轉換成 ParsePosNonezeroError::ParseInt();而如果 parsing 沒問題,但數值本身是 0 或負整數的話,就要回傳 ParsePosNonezeroError::Creation()(依據數值是 0 或負整數,會代不同的 error code)。

Conversion 的部份很單純:

impl ParsePosNonzeroError {
    fn from_creation(err: CreationError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::Creation(err)
    }

    fn from_parsing(err: ParseIntError) -> ParsePosNonzeroError {
        ParsePosNonzeroError::ParseInt(err)
    }
}

比較有趣的是應用的部份。

解法一

用 pattern match。無趣了點,但至少很清楚。

fn parse_pos_nonzero(s: &str)
    -> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
{
    let x = match s.parse() {
        Ok(i) => i,
        Err(e) => return Err(ParsePosNonzeroError::from_parsing(e)),
    };
    // PositiveNonzeroInteger::new() 回傳的 error type 是 CreationError,
    // 因此需要用 map_err 轉換成 ParsePosNonezeroError。
    PositiveNonzeroInteger::new(x)
        .map_err(ParsePosNonzeroError::from_creation)
}

解法二

利用 ? 簡化解法一。重點是要先做完 map_err() 後才加 ?

fn parse_pos_nonzero(s: &str)
    -> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
{
    let x = s.parse().map_err(ParsePosNonzeroError::from_parsing)?;
    PositiveNonzeroInteger::new(x)
        .map_err(ParsePosNonzeroError::from_creation)
}

解法三

想要用一個 expression 解決?這不就來了嗎?用 and_then() 來串接。

fn parse_pos_nonzero(s: &str)
    -> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
{
    s.parse()
        .map_err(ParsePosNonzeroError::from_parsing)
        .and_then(|x| {
            PositiveNonzeroInteger::new(x)
                .map_err(ParsePosNonzeroError::from_creation)
        })
}