当我想使用Result时匹配expect& Result

时间:2017-01-02 23:36:06

标签: rust

我每晚都在使用Rust 1.15,并且根据std::io::Result<std::fs::DirEntry>每个dir_contents_iterator是对应一个文件还是在DirEntry名为Err的迭代器上编写一些代码。一个文件夹(let (dir_list, file_list): (Vec<std::io::Result<DirEntry>>, Vec<std::io::Result<DirEntry>>) = dir_contents_iterator.partition(|entry_result| { match entry_result { Ok(entry) => { entry .file_type() .and_then(|file_type| Ok(file_type.is_dir())) .unwrap_or(false) }, Err(_) => false } }); 值已排序到文件列表中):

error[E0308]: mismatched types
   --> src/main.rs:179:13
    |
179 |             Ok(entry) => {
    |             ^^^^^^^^^ expected reference, found enum `std::result::Result`
    |
    = note: expected type `&std::result::Result<std::fs::DirEntry, std::io::Error>`
    = note:    found type `std::result::Result<_, _>`

error[E0308]: mismatched types
   --> src/main.rs:185:13
    |
185 |             Err(_) => false
    |             ^^^^^^ expected reference, found enum `std::result::Result`
    |
    = note: expected type `&std::result::Result<std::fs::DirEntry, std::io::Error>`
    = note:    found type `std::result::Result<_, _>`

此代码无法使用以下两个错误进行编译:

Err

我最终通过重写代码来解决我的问题,在文件和文件夹之间进行分区之前先将&Result值分区。这允许从显示的代码中删除匹配,现在编译。但是为了理解,我仍然想知道为什么我的原始匹配分支臂期望Result引用而不是接受Err(_) => false,尤其是在第二个分支臂的情况下({{ 1}})甚至不使用该值!

Gitter如果我遗漏了任何有助于解释问题的细节。

1 个答案:

答案 0 :(得分:1)

将此作为MCVE(您应该提供):

use std::fs::{self, DirEntry};

fn main() {
    let dirs = fs::read_dir("/tmp").expect("Nope");

    let (dir_list, file_list): (Vec<std::io::Result<DirEntry>>, Vec<std::io::Result<DirEntry>>) =
        dirs.partition(|entry_result| {
            match entry_result {
                Ok(entry) => {
                    entry.file_type()
                        .and_then(|file_type| Ok(file_type.is_dir()))
                        .unwrap_or(false)
                }
                Err(_) => false,
            }
        });
}

然后您可以print out the type of the variable

dirs.partition(|entry_result| {
    let () = entry_result;
    false
});

表明entry_result&std::result::Result<std::fs::DirEntry, std::io::Error>

答案

  

为什么我的原始匹配分支机构需要&Result参考

是因为你给它一个&Result

为了完整性,您可以取消引用变量,然后引用组件:

match *entry_result {
    Ok(ref entry) => {

这是多余的:

.and_then(|file_type| Ok(file_type.is_dir()))

因为它可以是map

.map(|m| m.is_dir())

还有一些清理工作:

use std::fs;

fn main() {
    let dirs = fs::read_dir("/tmp").expect("Nope");

    let (dir_list, file_list): (Vec<_>, Vec<_>) =
        dirs.partition(|entry_result| {
            entry_result.as_ref()
                .ok()
                .and_then(|entry| entry.file_type().ok())
                .map(|ft| ft.is_dir())
                .unwrap_or(false)
        });
}
  

我的印象是*ref会互相撤消。

*ref might undo each other,但这仅适用于相同值的情况。这里,我们是模式匹配,因此我们对取消引用的值采用&Result和模式匹配。然后我们引用里面的值 Result,所以没有任何东西被移动,但我们不会解除引用并重新引用相同的东西。