首页 > 解决方案 > 当对 None 值调用 unwrap 时,try 块中的代码仍然会出现恐慌

问题描述

#![feature(try_blocks)]
pub fn is_valid(code: &str) -> bool {
    let result: Result<bool, ()> = try {
        code.chars()
            .filter(|x| !x.is_whitespace())
            .map(|x| x.to_digit(10).unwrap())
            .rev()
            .enumerate()
            .map(|(i, num)| match i % 2 != 0 {
                true => {
                    let doubled = 2 * num;
                    match doubled > 9 {
                        true => doubled - 9,
                        false => doubled,
                    }
                }
                false => num,
            })
            .sum::<u32>()
            % 10
            == 0
    };
    match result {
        Ok(value) => value,
        Err(_) => false,
    }
}

在某些输入上,这个程序会出现恐慌,我不明白为什么。to_digit返回一个,Option但它被解包,并且None应该被try块捕获。我的理解是,如果.unwrap在一个值上调用了None,try 块将返回 a Result::Error,最终match将转换为false

我是 Rust 的新手!

我确实尝试x.to_digit(10).ok_or("Error").unwrap()将它变成 aResult而不是 a Option,但它没有任何区别。

标签: rust

解决方案


我的理解是,如果在 None 值上调用 .unwrap,try 块将返回 Result::Err

实际上没有:来自文档

如果 self 值等于 None 会发生恐慌。

'Panic' 与返回Result::Err. 恐慌旨在用于不可恢复的错误,而返回 aResult::Err用于日常潜在的可恢复错误。有关差异的更多讨论,请参阅 rust book 中的错误处理章节。

正如您所暗示的那样,unwrap您可以使用ok_or将其转换Option为 a Result

x.to_digit(10).ok_or("Error")?

请注意,我放了一个“?” 最后,而不是unwrap您尝试过的。的效果?是:

  • 如果值为 aResult::Err则从封闭函数或 try 块返回
  • 如果值为 aResult::Ok那么它被解包。

它脱糖是这样的:

match x.to_digit(10).ok_or("Error") {
    Err(e) => return Err(e),
    Ok(v) => v
}

正如评论中的某些人所提到的,如果您是 rust 新手,最好远离不稳定的功能,尽管我认为这不是导致此问题的原因。


推荐阅读