什么是Rust的解包,它用于什么?

Ang*_*gel 30 rust

我有这个代码使用.unwrap():

fn main() {
    let paths = std::fs::read_dir("/home/user").unwrap();

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

    }
}
Run Code Online (Sandbox Code Playgroud)

看了之后的定义unwrap,

pub fn unwrap(self) -> T {
  match self {
        Ok(t) => t,
        Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
    }
}
Run Code Online (Sandbox Code Playgroud)

签名read_dir

pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>
Run Code Online (Sandbox Code Playgroud)

我是否正确理解unwrap返回T传入的类型Result

rod*_*igo 41

在Rust中,当你有一个可能返回T或失败的操作时,你将得到一个类型的值Result<T,E>Option<T>(E如果有一个有趣的错误,将是错误条件).

如果有的话,该功能unwrap(self) -> T将为您提供嵌入式功能T.相反,如果不存在T,但一个ENone然后它会恐慌.

当您确定没有错误时,最好使用它.如果情况并非如此,通常情况下,模式匹配错误或使用try!宏运 ?算符转发错误会更好.

在您的示例中,调用read_dir()返回a,io::Result<ReadDir>因为打开目录可能会失败.并且迭代打开的目录会返回多个类型的值,io::Result<DirEntry>因为读取目录可能也会失败.

有了它会是这样的:try! ?

fn main2() -> 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 = main2();

    if let Err(e) = res {
        println!("Error: {}", e);
    }
}
Run Code Online (Sandbox Code Playgroud)

看看每个错误案例是如何检查的.

(更新为使用?而不是try!().宏仍然有效,但?新代码首选).

  • @RajeevRanjan:想想打开文件的例子:它可能会失败,因为你缺少权限,或者因为文件不存在,或者因为你请求了写权限而且它是只读的,或者因为文件系统已经损坏,或者是一个远程文件系统,网络已关闭......这很有趣!你可能想知道它失败的原因.OTOH,查找哈希表或字典中的值,如果它不存在,那就是它,它不是一个有趣的错误,并且没有额外的错误代码或数据.第一种情况是`Result <T,E>`,第二种情况是`Option <T>`. (5认同)
  • @SerakShiferaw:嗯,“unwrap()”的替代方法是使用“?”运算符。错误和失败只是编程生活中的一个事实。其他语言要么使用异常、错误代码,要么直接忽略任何错误……它们都有优点和缺点。 (5认同)
  • Rust 应该寻找这个垃圾的替代品。有时我会看到一些像 a.unwrap().b.unwrap().c 这样的代码,它一团糟。 (3认同)
  • 感谢@rodrigo 的精彩解释。“有趣的错误”到底是什么意思——一个已知的或可捕获的错误(如在其他语言中)? (2认同)
  • @Ben:太多的`unwrap()`是草率编程的标志,如果它是原型或运行后丢弃的程序,那么这是可以的。一些不能(或不应该)失败的`unwrap()`是可以的,例如`NonZeroU32::new(1).unwrap()`:如果你的假设是错误的并且失败了,程序会出现恐慌,这是一种错误-检查abort,这是正确的结果。 (2认同)

Yil*_*maz 14

问题是从文件中读取一行会产生潜在的错误类型。类型是

       Result<String,std::io::Error>
Run Code Online (Sandbox Code Playgroud)

Result是一个枚举。结果中有两个潜在值,它们用于错误处理和管理。第一个值是Err. 如果填充 Err,则调用的函数中存在错误。另一个潜在的选择是Ok。Ok 包含一个值。

enum Result<T, E> {
    Ok(T),
    Err(E),
}
Run Code Online (Sandbox Code Playgroud)

枚举是一种“复杂类型”,而不是单个值。为了获得我们正在寻找的值,我们使用unwrap()解包该值。

unwrap()此处用于快速处理错误。它可以用于任何返回Resultor的函数Option(Option 也是枚举)。如果函数返回 Ok(value),您将获得该值。如果函数返回 Err(error),程序就会出现紧急情况。例如这会恐慌:

fn main() {
    let result: Result<i32, &str> = Err("Unknown error");
    let value = result.unwrap(); // This line will cause a panic because result is Err,
}
Run Code Online (Sandbox Code Playgroud)

恐慌是不可取的(在测试环境中使用是可以的)。最好使用matchif let、 或之类的方法unwrap_or()来优雅地处理成功和错误情况,从而允许更受控的错误处理而不会引起恐慌。例如:

fn main() {
  let result: Result<i32, &str> = Err("Error occurred");

  let value = match result {
    Ok(val) => val,    // If result is Ok, return the value
    Err(err) => {
        println!("Error: {}", err);
        //returning a default value of 0
        0
    }
};
  println!("here is the default value {}",value)

}
Run Code Online (Sandbox Code Playgroud)

或者

fn main() {
 let result: Result<i32, &str> = Err("Error occurred");
let value = if let Ok(val) = result {
    val    // If result is Ok, return the value
} else {
    println!("Error occurred"); // Handle the error case
    // Return a default value or perform other error handling logic
    // Here, returning a default value of 0
    0
};
println!("here is the value {}",value)
    
}
Run Code Online (Sandbox Code Playgroud)