Reputation: 745
I am trying to:
Option<&str>
from somewhere, and build a PathBuf
from it.None
, print some message, and return.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;
}
}
The pattern matching in the above snippet doesn't work because the value has been moved in the map_or
combinator:
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
I can do something like this, but it doesn't feel very "idiomatic" because of the unwrap
and multiple if
clauses:
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);
}
Could there be a better to solve this?
Upvotes: 0
Views: 1296
Reputation: 1649
PathBuf
implements FromStr
trait, so you can use it, in combination with powerful pattern matching.
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 => {}
};
}
Upvotes: 1
Reputation: 40794
If the closure in .map(...)
(or any similar functions on an Option
) doesn't need ownership of the value in the option (i.e. it only needs a reference to the value), you can always use option.as_ref()
or option.as_mut()
to turn an &Option<T>
or &mut Option<T>
into an Option<&T>
or Option<&mut T>
. Then calling .map()
will not take ownership because references are copyable, so it's just copied into the provided closure.
With this in mind, your code would be modified to be this:
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;
}
}
Upvotes: 2