Как использовать значение после вызова Option :: map? - PullRequest
0 голосов
/ 08 июня 2019

Я пытаюсь:

  1. Получить откуда-нибудь Option<&str> и построить из него PathBuf.
  2. Если None, напечатать сообщение иreturn.
  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 ]

1 голос
/ 08 июня 2019

Если для замыкания в .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;
    }
}
0 голосов
/ 08 июня 2019

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 => {}
    };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...