为什么要 try!() 和 ?在不返回选项或结果的函数中使用时不编译? [英] Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
问题描述
为什么这段代码不能编译?
use std::{fs, path::Path};fn 主(){让 dir = Path::new("../FileSystem");如果 !dir.is_dir() {println!("不是目录");返回;}对于 try!(fs::read_dir(dir)) 中的项目!{让文件 = 匹配项 {错误(e) =>{println!("错误:{}", e);返回;}好的(f) =>F,};打印!("");}println!("完成");}
这是我得到的错误
错误[E0308]:类型不匹配-->src/main.rs:11:17|11 |对于 try!(fs::read_dir(dir)) 中的项目!{|^^^^^^^^^^^^^^^^^^^^^^ 期望(),找到枚举`std::result::Result`|= 注意:预期类型`()`找到类型`std::result::Result<_, _>`= 注意:此错误源自当前 crate 之外的宏(在 Nightly 构建中,使用 -Z external-macro-backtrace 运行以获取更多信息)
我也试过问号运算符:
对于 fs::read_dir(dir) 中的项目?{
有不同的错误:
error[E0277]: `?` 操作符只能用在返回 `Result` 或 `Option`(或其他实现 `std::ops::Try`)-->src/main.rs:11:17|11 |对于 fs::read_dir(dir) 中的项目?{|^^^^^^^^^^^^^^^^^^ 不能在返回 `()` 的函数中使用 `?` 运算符|= help: 特性 `std::ops::Try` 没有为 `()` 实现= 注意:`std::ops::Try::from_error` 需要
以前版本的 Rust 在 std::ops::Carrier
我应该避免try!()
和吗?
?处理错误的最佳方法是什么?大多数情况下,我是这样做的:
match error_prone {错误(e) =>{println!("错误:{}", e);返回;},好的(f) =>F,};
但是如果我必须在 for
循环中使用它,那就一团糟
for i in match error_prone {//匹配代码} {//循环代码}
try!
是一个自动返回 Err
s 的宏;?
是几乎相同的语法,但它适用于任何实现 Try
特性.
截至 Rust 1.22.0,Option
实现了Try
,所以可以和?
一起使用.在此之前,?
只能用在返回 Result
的函数中.try!
继续仅适用于 Result
s.
从 Rust 1.26.0 起,main
允许返回一个实现 Termination
的值.在此之前,它不会返回任何值.
从 Rust 1.26.0 开始
如果您将 main
标记为返回 Result
,然后在所有成功"中返回 Ok(())
,则您的原始代码有效案例:
使用 std::{fs, io, path::Path};fn main() ->结果<(), io::Error>{让 dir = Path::new("../FileSystem");如果 !dir.is_dir() {println!("不是目录");返回 Ok(());}对于 fs::read_dir(dir) 中的项目?{让文件 = 匹配项 {错误(e) =>{println!("错误:{}", e);返回 Ok(());}好的(f) =>F,};打印!("");}println!("完成");行(())}
在那之前
这是您如何将代码转换为使用 ?
:
use std::{error::Error, fs, path::Path};fn print_dir_contents() ->结果<字符串,框<错误>>{让 dir = Path::new("../FileSystem");如果 !dir.is_dir() {return Err(Box::from("不是目录!"));}用于进入 fs::read_dir(dir)?{let path = entry?.path();让 file_name = path.file_name().unwrap();println!("{}", file_name.to_string_lossy());}好的(完成".进入())}fn 主(){匹配 print_dir_contents() {好的 =>println!("{}", s),错误(e) =>println!("错误:{}", e.to_string()),}}
这里有很多您可能没想到的错误处理 - 其他语言往往不需要它!但它们存在于其他语言中——Rust 只是让你知道它.以下是错误:
<块引用>条目?
IO 错误可能在迭代过程中发生.
<块引用>path.file_name().unwrap()
并非所有路径都有文件名.我们可以解包
这个,因为read_dir
不会给我们一个没有文件名的路径.
file_name.to_string_lossy()
您也可以 to_str
并抛出错误,但这样做更好.存在此错误是因为并非所有文件名都是有效的 Unicode.
try!
和 ?
将错误放入返回值中,将它们转换为 Box::Error
.返回所有可能出错的合并错误实际上更合理.幸运的是 io::Error
是正确的类型:
使用 std::io;//...fn print_dir_contents() ->结果<字符串,io::错误>{//...如果 !dir.is_dir() {return Err(io::Error::new(io::ErrorKind::Other, "不是目录!"));}//...}
坦率地说,这个检查已经在 fs::read_dir
中,所以你实际上可以完全删除 if !dis.is_dir
:
使用 std::{fs, io, path::Path};fn print_dir_contents() ->结果<字符串,io::错误>{让 dir = Path::new("../FileSystem");用于进入 fs::read_dir(dir)?{let path = entry?.path();让 file_name = path.file_name().unwrap();println!("{}", file_name.to_string_lossy());}好的(完成".进入())}fn 主(){匹配 print_dir_contents() {好的 =>println!("{}", s),错误(e) =>println!("错误:{}", e.to_string()),}}
Why does this code not compile?
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");
}
This is the error I get
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)
I also tried the question mark operator:
for item in fs::read_dir(dir)? {
Which had a different error:
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`
Previous versions of Rust had a similar error about std::ops::Carrier
Should I avoid try!()
and ?
? What is the best way to handle errors? Mostly I do it like this:
match error_prone {
Err(e) => {
println!("Error: {}", e);
return;
},
Ok(f) => f,
};
But if I have to use that in a for
loop, it's a complete mess
for i in match error_prone {
// match code
} {
// loop code
}
try!
is a macro that returns Err
s automatically; ?
is syntax that does mostly the same thing, but it works with any type that implements the Try
trait.
As of Rust 1.22.0, Option
implements Try
, so it can be used with ?
. Before that, ?
could only be used in functions that return a Result
. try!
continues to only work with Result
s.
As of Rust 1.26.0, main
is allowed to return a value that implements Termination
. Before that, it doesn't return any value.
As of Rust 1.26.0
Your original code works if you mark main
as returning a Result
and then return Ok(())
in all the "success" cases:
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(())
}
Before that
This is how you might transform your code to use ?
:
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()),
}
}
There's a lot of error handling here that you might not expect - other languages don't tend to require it! But they exist in other languages - Rust just makes you know it. Here are the errors:
entry?
IO errors can happen during iteration.
path.file_name().unwrap()
Not all paths have file names. We can unwrap
this because read_dir
won't give us a path without a file name.
file_name.to_string_lossy()
You can also to_str
and throw an error, but it's nicer to do this. This error exists because not all file names are valid Unicode.
try!
and ?
throw errors into the return value, converting them to Box::Error
. It's actually more reasonable to return an amalgamated error of all the things that can go wrong. Luckily io::Error
is just the right type:
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!"));
}
// ...
}
Frankly, though, this check is already in fs::read_dir
, so you can actually just remove the if !dis.is_dir
altogether:
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()),
}
}
这篇关于为什么要 try!() 和 ?在不返回选项或结果的函数中使用时不编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!