Reputation: 1500
I just found myself writing this:
fn init_timestamps(dir: &PathBuf, file_timestamps: &'static HashMap<PathBuf,Duration>) {
match fs::read_dir(dir) {
Ok(iter) => iter.for_each(|result| match result {
Ok(entry) => {
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
init_timestamps(&entry.path(), file_timestamps);
} else {
match entry.metadata() {
Ok(md) => match md.modified() {
Ok(modified) => {
locked_timestamps.insert(entry.path(), modified.duration_since(SystemTime::UNIX_EPOCH).unwrap());
},
Err(_) => ()
},
Err(_) => ()
};
}
},
Err(_) => ()
}),
Err(_) => ()
};
}
And I have to ask: is there a better pattern I'm missing? I tried using .map()
at each level, which looked slightly better but gave me compiler warnings about unused Results. What I'm wanting to do, in this general case, is "if this chain of Results (or Options) exists all the way down, do X. otherwise, do nothing." I've also run into similar situations where I want to coerce "failed" points in the chain to false
(there's a boolean check at the fullest depth).
This actually could be seen as Rust's version of the null-check problem addressed with the null-coalescing operator in other languages such as Kotlin.
Upvotes: 2
Views: 924
Reputation: 70297
You're looking for the ?
operator, designed for this exact task.
foo()?
is equivalent to
match foo() {
Ok(t) => t
Err(e) => return Err(e.into()),
}
So you can just throw ?
at the end of anything that returns a Try
implementation. You'll have to make your function return Result<(), E>
, but that's just as well because then your function will report its errors rather than failing silently.
Upvotes: 5