为什么要 try!() 和 ?在不返回选项或结果的函数中使用时不编译? [英] Why do try!() and ? not compile when used in a function that doesn't return Option or Result?

查看:18
本文介绍了为什么要 try!() 和 ?在不返回选项或结果的函数中使用时不编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这段代码不能编译?

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! 是一个自动返回 Errs 的宏;? 是几乎相同的语法,但它适用于任何实现 Try 特性.

截至 Rust 1.22.0Option实现了Try,所以可以和?一起使用.在此之前,? 只能用在返回 Result 的函数中.try! 继续仅适用于 Results.

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 Errs 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 Results.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆