调用Option :: map后如何使用值?

时间:2019-06-07 22:08:51

标签: rust

我正在尝试:

  1. 从某个地方获取一个Option<&str>,然后从其中构建一个PathBuf
  2. 如果为None,则打印一些消息,然后返回。
  3. 如果该路径不是目录,则输出一条消息,指出该路径不是目录,然后返回。
  4. 如果一切正常,请继续执行程序。
use std::path::PathBuf;

fn it_works() {
    let path_str = Some("/tmp/abc");
    let path = path_str.map(|s| PathBuf::from(s));
    if !path.map_or(false, |p| p.is_dir()) {
        match path {
            Some(p) => println!("The folder {:?} is not a directory!", p),
            None => println!("The repository folder is not set!"),
        }
        return;
    }
}

上述代码段中的模式匹配无效,因为该值已在map_or组合器中移动:

error[E0382]: use of moved value
 --> src/lib.rs:8:18
  |
5 |     let path = path_str.map(|s| PathBuf::from(s));
  |         ---- move occurs because `path` has type `std::option::Option<std::path::PathBuf>`, which does not implement the `Copy` trait
6 |     if !path.map_or(false, |p| p.is_dir()) {
  |         ---- value moved here
7 |         match path {
8 |             Some(p) => println!("The folder {:?} is not a directory!", p),
  |                  ^ value used here after move

我可以做这样的事情,但是由于unwrap和多个if子句,感觉不太“习惯”:

let path_str = Some("/tmp/abc");
let path = path_str.map(|s| PathBuf::from(s));
if path.is_none() {
    println!("The repository folder is not set!");
    return;
}
let p = path.unwrap();
if !p.is_dir() {
    println!("The folder {:?} is not a directory!", p);
}

有更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

如果.map(...)中的闭包(或Option上的任何类似函数)不需要对该选项中的值拥有所有权(即,只需要引用该值),则可以始终使用option.as_ref()option.as_mut()&Option<T>&mut Option<T>变成Option<&T>Option<&mut T>。然后调用.map()不会拥有所有权,因为引用是可复制的,因此它只是复制到提供的闭包中。

考虑到这一点,您的代码将被修改为:

fn it_works() {
    let path_str = Some("/tmp/abc");
    let path = path_str.map(|s| PathBuf::from(s));
    if !path.as_ref().map_or(false, |p| p.is_dir()) {
        //  ^^^^^^^^^ using .as_ref() here
        //                          ^^^ now p is a '&PathBuf' instead of 'PathBuf'

        match path {
        //    ^^^^ we didn't take ownership so compiler doesn't complain here

            Some(p) => println!("The folder {:?} is not a directory!", p),
            None => println!("The repository folder is not set!"),
        }
        return;
    }
}

答案 1 :(得分:0)

PathBuf实现了FromStr特征,因此您可以将其与强大的模式匹配结合使用。

fn it_works() {
    use std::path::*;
    use std::str::FromStr;

    let path_str: Option<&str> = Some("/tmp/abc");
    match path_str.map(PathBuf::from_str) {
        Some(Ok(p)) => if !p.is_dir() {},
        Some(Err(e)) => {}
        None => {}
    };
}