gpt4 book ai didi

rust - 为什么要尝试!()和?在不返回Option或Result的函数中使用时无法编译?

转载 作者:行者123 更新时间:2023-12-03 11:46:47 25 4
gpt4 key购买 nike

为什么此代码无法编译?

use std::{fs, path::Path};

fn main() {
let dir = Path::new("../FileSystem");

if !dir.is_dir() {
println!("Is not a directory");
return;
}

for item in try!(fs::read_dir(dir)) {
let file = match item {
Err(e) => {
println!("Error: {}", e);
return;
}
Ok(f) => f,
};

println!("");
}

println!("Done");
}

这是我得到的错误

error[E0308]: mismatched types
--> src/main.rs:11:17
|
11 | for item in try!(fs::read_dir(dir)) {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
|
= note: expected type `()`
found type `std::result::Result<_, _>`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

我还尝试了问号运算符:
for item in fs::read_dir(dir)? {

哪个有不同的错误:

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:11:17
|
11 | for item in fs::read_dir(dir)? {
| ^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`

先前版本的Rust具有关于 std::ops::Carrier的类似错误

我应该避免使用 try!()?吗?处理错误的最佳方法是什么?通常,我这样做是这样的:
match error_prone {
Err(e) => {
println!("Error: {}", e);
return;
},
Ok(f) => f,
};

但是,如果我必须在 for循环中使用它,那就太麻烦了
for i in match error_prone {
// match code
} {
// loop code
}

最佳答案

try!是自动返回Err的宏; ?是一种语法,其功能大致相同,但可与实现 Try 特征的任何类型一起使用。

Rust 1.22.0开始,Option实现Try,因此可以与?一起使用。在此之前,?仅可用于返回Result的函数中。 try!继续仅适用于Result

Rust 1.26.0开始,允许main返回实现Termination的值。在此之前,它不返回任何值。

从Rust 1.26.0开始

如果您将main标记为返回Result,然后在所有“成功”情况下返回Ok(()),则您的原始代码将起作用:

use std::{fs, io, path::Path};

fn main() -> Result<(), io::Error> {
let dir = Path::new("../FileSystem");

if !dir.is_dir() {
println!("Is not a directory");
return Ok(());
}

for item in fs::read_dir(dir)? {
let file = match item {
Err(e) => {
println!("Error: {}", e);
return Ok(());
}
Ok(f) => f,
};

println!("");
}

println!("Done");
Ok(())
}

在那之前

这就是您可以将代码转换为使用 ?的方式:
use std::{error::Error, fs, path::Path};

fn print_dir_contents() -> Result<String, Box<Error>> {
let dir = Path::new("../FileSystem");

if !dir.is_dir() {
return Err(Box::from("Is not a directory!"));
}

for entry in fs::read_dir(dir)? {
let path = entry?.path();
let file_name = path.file_name().unwrap();
println!("{}", file_name.to_string_lossy());
}

Ok("Done".into())
}

fn main() {
match print_dir_contents() {
Ok(s) => println!("{}", s),
Err(e) => println!("Error: {}", e.to_string()),
}
}

您可能不会想到很多错误处理-其他语言往往不需要它!但是它们以其他语言存在-Rust只是让您知道它。错误如下:

entry?


IO错误可能在迭代过程中发生。

path.file_name().unwrap()


并非所有路径都有文件名。我们可以使用 unwrap,因为 read_dir不会为我们提供没有文件名的路径。

file_name.to_string_lossy()


您也可以 to_str并引发错误,但是这样做更好。存在此错误是因为并非所有文件名都是有效的Unicode。
try!?将错误放入返回值中,并将它们转换为 Box::Error。实际上,返回所有可能出错的错误的合并错误更为合理。幸运的是, io::Error是正确的类型:
use std::io;

// ...

fn print_dir_contents() -> Result<String, io::Error> {
// ...

if !dir.is_dir() {
return Err(io::Error::new(io::ErrorKind::Other, "Is not a directory!"));
}

// ...
}

坦白说,但是,此检查已经在 fs::read_dir中,因此您实际上可以完全删除 if !dis.is_dir:
use std::{fs, io, path::Path};

fn print_dir_contents() -> Result<String, io::Error> {
let dir = Path::new("../FileSystem");

for entry in fs::read_dir(dir)? {
let path = entry?.path();
let file_name = path.file_name().unwrap();
println!("{}", file_name.to_string_lossy());
}

Ok("Done".into())
}

fn main() {
match print_dir_contents() {
Ok(s) => println!("{}", s),
Err(e) => println!("Error: {}", e.to_string()),
}
}

关于rust - 为什么要尝试!()和?在不返回Option或Result的函数中使用时无法编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66062776/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com