首页 > 解决方案 > 调用 Option::map 后如何使用值?

问题描述

我在尝试着:

  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

我可以做这样的事情,但感觉不是很“惯用”,因为unwrapand 多个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);
}

有没有更好的办法来解决这个问题?

标签: rust

解决方案


如果闭包 in .map(...)(或 an 上的任何类似函数Option)不需要选项中的值的所有权(即它只需要对该值的引用),您始终可以使用option.as_ref()oroption.as_mut()将 an &Option<T>or&mut Option<T>转换为Option<&T>or 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;
    }
}

推荐阅读