为什么此代码无法编译?

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)
 


我还尝试了问号运算符: br />
 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!()??处理错误的最佳方法是什么?大多数情况下,我是这样做的:

for item in fs::read_dir(dir)? {


但是如果我必须在for循环中使用它,那就太麻烦了

match error_prone {
    Err(e) => {
        println!("Error: {}", e);
        return;
    },
    Ok(f) => f,
};


评论

尝试!是自动返回Errs的宏。您不能在main中使用它,因为main不返回任何内容。

Aaaahn解释了很多。.谢谢你!在这种特定情况下,我将如何处理错误?不必诉诸上述奇怪的match语法

也可以看看。通常,懒惰的方法是将代码粘贴在您从main调用的某些包装函数中,该包装函数返回Result >,然后在main中解包或处理该包装。

基本上,错误包装会引起恐慌吗?

println!(“ {}”,path.unwrap()。path()。file_name()。unwrap()。to_str()。unwrap());真? :p

#1 楼

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

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

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

从Rust 1.26.0起

如果将main标记为返回Result,然后在所有“成功”的情况:

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(())
}


在此之前

这是将代码转换为使用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不会为我们提供没有文件名的路径。错误,但这样做更好。因为并非所有文件名都不是有效的Unicode,所以存在此错误。实际上,返回所有可能出错的错误的合并错误更为合理。幸运的是,read_dir恰好是正确的类型:

file_name.to_string_lossy()


但是,坦白地说,此检查已在to_str中,因此您实际上可以完全删除try!
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!"));
    }

    // ...
}


评论


使它适用于其他类型的错误?运算符,我需要更改为fn main()-> Result <(),Box >> {阅读更多blog.burntsushi.net/rust-error-handling / ...

– rofrol
18年8月2日在13:07



#2 楼

ques_in_main RFC是最近合并的。完成后,如果将try!()调用替换为?运算符,则问题中的语法确实可以正常编译并按预期工作。

#3 楼

从Rust 1.26开始,Rust支持main()的返回值,因此支持在定义?返回try!()时在main()中使用错误检查运算符main()(或等效的Result宏) br />
extern crate failure;
use failure::Error;
use std::fs::File;

type Result<T> = std::result::Result<T, Error>;

fn main() -> Result<()> {
    let mut _file = File::open("foo.txt")?; // does not exist; returns error
    println!("the file is open!");
    Ok(())
}


以上内容编译并返回文件未找到错误(假设foo.txt在本地路径中不存在)。

#4 楼

Veedrac的回答对我也有帮助,尽管OP的问题略有不同。在阅读Rust文档时,我看到了以下片段:会得到类似的错误。如果将代码包装在处理错误的函数中,上述代码段将起作用:

use std::fs::File;
use std::io::prelude::*;

let mut file = File::open("foo.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
assert_eq!(contents, "Hello, world!");


PS。我正在学习Rust,因此这些片段不适合用作Rust编码:)