在Rust中,unwrap是什么意思,它有什么用途?

164
我有一个使用.unwrap()的代码。
fn main() {
    let paths = std::fs::read_dir("/home/user").unwrap();

    for path in paths {
        println!("Name: {}", path.unwrap().path().display());

    }
}

在查看了解包的定义之后,
pub fn unwrap(self) -> T {
  match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
    }
}

并且 read_dir的签名

pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>

我理解得正确吗,unwrap 返回传入 ResultT 类型吗?


7
不需要因为英语不好而道歉;只要有人能理解问题,我们就可以整理它。只需确保搜索以前的问题并解释为什么您的问题不是它们的重复即可。 - Shepmaster
@Shepmaster,如果我早先看到了第一个链接,但我发现它更像是一件事情和另一件事情之间的区别,并且有关“选项”的讨论,我不确定我们是否在谈论同一个“结果”,现在我更好地理解了,感谢您的回复,现在可以以任何方式理解为重复内容,在第二个链接中我之前没有看到过,感谢您的一切。 - Angel Angel
3个回答

197
在Rust中,当你进行一个可能会返回 T 或失败的操作时,你将会得到一个类型为Result<T,E>Option<T>的值 (在出现有趣错误的情况下 E 将是错误条件)。
函数 unwrap(self) -> T 将会给你嵌套的T,如果存在的话。如果没有 T,而是一个 ENone,那么它将会导致 panic。
当你确信不存在错误时,最好使用它。如果不是这种情况,通常最好通过模式匹配来处理错误或使用try! ? 运算符转发错误。
在你的示例中,调用 read_dir() 返回一个 io:: Result<ReadDir> ,因为打开目录可能失败。并且迭代已打开的目录将返回多个类型为 io:: Result<DirEntry> 的值,因为读取目录也可能失败。
使用 try! ? 的代码大致如下:
fn try_main() -> std::io::Result<()> {
    let entries = std::fs::read_dir("/home/user")?;

    for entry in entries {
        println!("Name: {}", entry?.path().display());

    }
    Ok(())
}

fn main() {
    let res = try_main();

    if let Err(e) = res {
        println!("Error: {}", e);
    }
}

看看每个错误情况是如何被检查的。

(更新为使用?而不是try!()。宏仍然可以工作,但对于新代码,建议使用?)。


2
感谢@rodrigo的精彩解释。你所说的“有趣的错误”究竟是什么意思 - 是已知或可捕获的错误(如其他语言中的错误)? - Rajeev Ranjan
27
例如考虑打开文件:它可能因为权限不足或者文件不存在或者你请求写入但是只读,或者文件系统损坏或者是远程文件系统而网络故障等原因导致失败……这很有意思!也许你想知道为什么会失败。另一方面,在哈希表或字典中查找值,如果没有找到,那就是了,这不是一个有趣的错误,也没有额外的错误代码或数据可以获得。第一种情况将是“Result<T,E>”,第二种情况将是“Option<T>”。 - rodrigo
6
Rust 应该寻找替代这个玩意的方法。有时我会看到一些代码,像 a.unwrap().b.unwrap().c 这样的,太混乱了。 - Serak Shiferaw
9
“unwrap()”的替代方法是使用“?”操作符。错误和故障只是编程生活中的一个事实。其他语言要么使用异常,错误代码,要么直接忽略任何错误...它们都有其优缺点。 - rodrigo
7
@Ben: 过多地使用 unwrap() 是粗糙编程的标志,如果是原型或运行并丢弃的程序,这是可以接受的。一些不可能(或不应该)失败的 unwrap() 是可以接受的,例如 NonZeroU32::new(1).unwrap():如果您的假设是错误的并且它失败了,程序将会崩溃,这是一种类似于 bug-check abort 的正确结果。 - rodrigo
显示剩余7条评论

11
读取文件中的一行会产生一个潜在错误类型。这个类型是:
       Result<String,std::io::Error>

Result 是一个枚举类型。在 Result 中有两个潜在值,它们通常用于错误处理和管理。第一个值是 Err。如果 Err 被赋值,说明调用的函数出现了错误。另一个可能的选择是 Ok。Ok 包含一个值。

enum Result<T, E> {
    Ok(T),
    Err(E),
}

枚举是一种复杂类型,而不是单个值。为了获取我们所需的值,我们使用 unwrap() 来解包该值。

unwrap() 用于快速处理错误,它可用于返回 ResultOption(Option也是一个枚举)的任何函数。如果函数返回 Ok(value),将获得该值。如果函数返回 Err(error),程序将会出现错误。


-3

在Result或Option上调用unwrap()的替代方法。

该宏旨在用于所有情况下,其中一个会在出现错误时解包Result或Option以故意引发panic,例如在测试用例中。这样的解包不会给出代码中精确的失败点,而是指示Rust核心库中的某些行号。该宏提供了一个精确的失败点,并为易于查看而装饰了失败信息。


什么宏?这看起来像是你在引用一些文档。 - Chayim Friedman
是的,我做到了!现在从文档中理解它变得非常容易。如果您需要更多详细信息,可以通过abdulrahim.klis@amygdal.com与我联系,我可以向您解释。Rust是一种很棒的编程语言! - Abdulrahim Klis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接