Reputation: 101
I am trying to map value inside Option and if it is missing then I want to return Error. Currently I am using approach:
pub fn unmarshall_root(opt: Option<String>) -> Result<String, io::Error> {
let res = match opt {
Some(s) => unmarshall_child(s)?,
None => return Err(new_error(String::from("input must be defined"))),
};
Ok(res)
}
pub fn unmarshall_child(o: String) -> Result<String, io::Error> {
Ok(o)
}
It works fine, but want something more elegant. Something like:
opt.map(|it| unmarshall_child(it)?)
.ok_or_else(Err(new_error(String::from("input must be defined"))))
Which cannot be compiled (err message: "cannot use the ?
operator in a closure that returns"). Any recommendation for more elegant approach?
EDIDTED: Thanks for all proposed approaches. I have another question, how to handle situation more elegantly when I do not to fail if value is empty:
pub fn unmarshall_root(opt: Option<String>) -> Result<Option<String>, io::Error> {
let res = match opt {
Some(s) => Some(unmarshall_child(s)?),
None => None,
};
Ok(res)
}
Upvotes: 0
Views: 1567
Reputation: 503855
Removing the unnecessary unwrapping-and-rewrapping, you'd have:
pub fn unmarshall_root(opt: Option<String>) -> Result<String, io::Error> {
match opt {
Some(s) => unmarshall_child(s),
None => Err(new_error(String::from("input must be defined"))),
}
}
This is already pretty straightforward. A common rearrangement (if you need to operate on s
a bit more than once) is:
pub fn unmarshall_root(opt: Option<String>) -> Result<String, io::Error> {
let s = if let Some(s) = opt {
s
} else {
return Err(new_error(String::from("input must be defined")));
};
// ...
unmarshall_child(s)
}
This gives good flexibility without over-closurifying the code.
When let-else
is finalized, this can be written:
pub fn unmarshall_root(opt: Option<String>) -> Result<String, io::Error> {
let Some(s) = opt else {
return Err(new_error(String::from("input must be defined")));
};
unmarshall_child(s)
}
But if you really must one-line it, then:
pub fn unmarshall_root(opt: Option<String>) -> Result<String, io::Error> {
opt.ok_or_else(|| new_error(String::from("input must be defined")))
.and_then(unmarshall_child)
}
Upvotes: 0
Reputation: 70970
I'm not sure this is more elegant, but you can rewrite it like:
unmarshall_child(
opt.ok_or_else(|| new_error(String::from("input must be defined")))?,
)?
Upvotes: 1