Unwrap Result inside Optional [duplicate] - rust

This question already has answers here:
Is it possible to convert Option<Result<T, E>> to a Result<Option<T>, E> without using match?
(2 answers)
Closed 3 years ago.
Is there a canonical way to convert Option<Result<T>> to Result<Option<T>>?
fn optres_to_resopt<T>(optres: Option<Result<T>>) -> Result<Option<T>> {
if let Some(res) = optres {
match res {
Ok(v) => Ok(Some(v)),
Err(e) => Err(e),
}
} else {
Ok(None)
}
}

There is Option::transpose:
fn optres_to_resopt<T>(optres: Option<Result<T>>) -> Result<Option<T>> {
optres.transpose()
}
And BTW, the implementation is basically your function:
pub fn transpose(self) -> Result<Option<T>, E> {
match self {
Some(Ok(x)) => Ok(Some(x)),
Some(Err(e)) => Err(e),
None => Ok(None),
}
}

I would definitely use transpose(from the approved answer) but as an exercise here is a different version of implementation:
fn optres_to_resopt<T, E>(optres: Option<Result<T, E>>) -> Result<Option<T>, E> {
optres.map_or(Ok(None), |x| Ok(Some(x?)))
}
Playground
Since Result also has a transpose method too, it is easy to revert it back. As an alternative we can apply the same approach in this problem too:
fn resopt_optres<T, E>(resopt: Result<Option<T>, E>) -> Option<Result<T, E>> {
resopt
.map(|x| Some(Ok(x?)))
.unwrap_or_else(|x| Some(Err(x)))
}
Playground
Note : The idea in here is map_or(or unwap_or_else) has ability to change the enclosing type with a generic type.

Related

How to convert Vec<Result<Option<(u32, u32)>, Error>> to Result<HashMap<u32, 32>, Error> using iterator only(without for)?

Apologize for confusing title.
Say I have a user_ids: Vec<u32> and there is a function fn get_year(user_id: u32) -> Result<Option<u32>, Error>(this function involve db lookup`
And I would like to get years of all those user_ids and concert it into a hashmap where key is the id and value is the year. If it should return error immediately if there is one get_year return error.
I am able to get it working with for
use std::collections::HashMap;
#[derive(Debug)]
enum Error {
ConnectionFail
}
fn get_year(user_id: u32) -> Result<Option<u32>, Error> {
Err(Error::ConnectionFail)
}
fn get_age_lookup(user_ids: Vec<u32>) -> Result<HashMap<u32, u32>, Error> {
let mut age_lookup = HashMap::new();
for &user_id in user_ids.iter() {
let year_result = get_year(user_id)?;
match year_result {
None => (),
Some(year) => {age_lookup.insert(user_id, year);}
};
};
Ok(age_lookup)
}
fn main() {
let age_lookup = get_age_lookup(vec![1, 2, 3]);
println!("result: {:?}!", age_lookup);
}
But not able to do it without for. I am able to get it working but that require 2 iterators which is probably not efficient. I wonder if there is a way to make it work with only 1 iteration without for`?
fn get_age_lookup(user_ids: Vec<u32>) -> Result<HashMap<u32, u32>, Error> {
let age_tuples =
user_ids
.into_iter()
.map(|user_id| {
get_year(user_id)
.map(|year_result| match year_result {
None => None,
Some(year) => Some((user_id, year))
})
})
.collect::<Result<Vec<Option<(u32, u32)>>, Error>>()?;
Ok(age_tuples.into_iter().filter_map(|x| x).collect::<HashMap<u32, u32>>())
}
}
You are very close. The missing ingredient here is Result::transpose(), which turns a Result<Option<T>, E> into a Option<Result<T, E>>. You can filter_map() over that, which will eliminate the Ok(None) values and simultaneously unwrap the nested Option, so you'll have an iterator of Result<T, E> at that point. Finally, collect() can convert into a collection wrapped by a Result -- if any item in the sequence is Err, it will short-circuit and propagate the error.
fn get_age_lookup(user_ids: Vec<u32>) -> Result<HashMap<u32, u32>, Error> {
user_ids
.into_iter()
.map(|user_id| {
get_year(user_id)
.map(|year_result| match year_result {
None => None,
Some(year) => Some((user_id, year))
})
})
.filter_map(|x| x.transpose())
.collect()
}
(Playground)
As an aside, you can additionally simplify your match using the Option::map() method, which applies a transformation to Ok values. So this:
match year_result {
None => None,
Some(year) => Some((user_id, year))
}
Can become:
year_result.map(|year| (user_id, year))

How do I return a custom error from a splitn fn?

I've written this function to parse a comma-separated string and return either a <Vec<&str>> or a custom error:
fn parse_input(s: &str) -> Result<Vec<&str>, ParseError> {
match s.splitn(2, ',').next() {
Ok(s) => s.collect::<Vec<&str>>(),
Err(err) => Err(ParseError::InvalidInput)
}
}
The compiler gives me this response:
Ok(s) => s.collect::<Vec<&str>>(),
^^^^^ expected enum `Option`, found enum `Result`
...
Err(err) => Err(ParseError::InvalidInput)
^^^^^^^^ expected enum `Option`, found enum `Result`
My problem is that I don't understand how to change the code to satisfy the compiler. What is wrong with this function?
.next() returns an Option<&str>, i.e. Some(s) or None.
fn parse_input(s: &str) -> Result<Vec<&str>, ParseError> {
match s.splitn(2, ',').next() {
Some(s) => s.collect::<Vec<&str>>(),
None => Err(ParseError::InvalidInput),
}
}
Just like you wrapped the error with Err to make it a Result, the non-error needs to be wrapped with Ok.
fn parse_input(s: &str) -> Result<Vec<&str>, ParseError> {
match s.splitn(2, ',').next() {
Some(s) => Ok(s.collect::<Vec<&str>>()),
None => Err(ParseError::InvalidInput),
}
}
Whether it’s the pattern-matched Some(s) or the outer parameter s, s.collect() doesn’t make sense. Going by your description, maybe you want to split the string on commas, collect that into a Vec, and produce an error if the result doesn’t consist of exactly two parts?
fn parse_input(s: &str) -> Result<Vec<&str>, ParseError> {
let parts: Vec<_> = s.split(',').collect();
if parts.len() == 2 {
Ok(parts)
} else {
Err(ParseError::InvalidInput)
}
}
Maybe a pair would be better? Also, if more than one comma is acceptable and you just want to split on the first one, split_once fits perfectly.
fn parse_input(s: &str) -> Result<(&str, &str), ParseError> {
s.split_once(',').ok_or(ParseError::InvalidInput)
}

Is there an elegant way to rewrite getting or creating an Option using a `match` statement? [duplicate]

This question already has an answer here:
How to get an Option's value or set it if it's empty?
(1 answer)
Closed 2 years ago.
I boiled my code down to these lines:
#[derive(Debug)]
struct Config {
values: Vec<String>,
compiled: Option<Vec<String>>,
}
impl Config {
fn comp_values(&mut self) -> &Vec<String> {
if self.compiled.is_none() {
self.compiled = Some(self.values.clone());
}
self.compiled.as_ref().unwrap()
}
fn comp_values_match(&mut self) -> &Vec<String> {
match self.compiled {
Some(_) => self.compiled.as_ref().unwrap(),
None => {
self.compiled = Some(self.values.clone());
self.compiled.as_ref().unwrap()
}
}
}
}
fn main() {
let mut c = Config {
values: vec![String::from("a"), String::from("b")],
compiled: None,
};
println!("config before: {:?}", c);
println!("compiled: {:?}", c.comp_values());
println!("config after: {:?}", c);
}
What I would like to have is something like:
match self.compiled {
Some(v) => v,
None => {
// assemble v and assign it to self.compiled
v
},
}
just like in the closure chapter in the book. Is it possible in the book it only worked, because u32 implements the Copy trait? If I change the match line to match self.compiled.as_ref() the Some(v) => v, works. In the None arm I then can't assign like self.compiled = ... since I have have the variable 'open' (or referenced with self.compiled.as_ref()) in that block.
Are my assumptions correct? Is the comp_values() method the most elegant solution in that case?
Not a match statement, but I think you are looking for get_or_insert_with.

Returning value of enum [duplicate]

This question already has answers here:
How do you access enum values in Rust?
(6 answers)
How do I get an enum as a string?
(2 answers)
Closed 4 years ago.
I'm implementing FizzBuzz in Rust. I went from the simplest version to using an enum and I can't resolve it. I've read enums are very potent so I tried to use them to their fullest.
Here is my implementation:
use std::fmt;
fn main() {
for i in 1..100 {
println!("{}", fizzbuzz(i))
}
}
fn fizzbuzz(value: i32) -> Answer {
use crate::Answer::*;
return match (value % 3, value % 5) {
(0, 0) => FizzBuzz,
(0, _) => Fizz,
(_, 0) => Buzz,
(_, _) => Nothing(value),
};
}
enum Answer {
FizzBuzz,
Fizz,
Buzz,
Nothing(i32),
}
impl fmt::Display for Answer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use crate::Answer::*;
match self {
FizzBuzz => write!(f, "FizzBuzz"),
Fizz => write!(f, "Fizz"),
Buzz => write!(f, "Buzz"),
Nothing() => write!(f, "number passed to NoBuzz"),
}
}
}
I have 2 problems:
how to use the name of actual enum in match self block?
In Java, I could use just FizzBuzz.name() and it would print
"FizzBuzz" - is it possible in Rust?
is it possible to print that value I passed to Nothing in fizzbuzz
function?
You can derive a printable representation for debugging purposes with #[derive(Debug)]. This would let you print it out using println!("{:?}", self)
Example:
#[derive(Debug)]
enum Answer {
FizzBuzz,
Fizz,
Buzz,
Nothing(i32),
}
match self {
Nothing(_) -> /* ... */,
other -> println!("{:?}", other),
}
However, it's much more appropriate to write a Display instance yourself. You'll have to do the translation (Fizz -> "Fizz", etc) yourself, but then it will be in a centralized location and you can pass it to formatters like you've been doing.
To get the value out of the Nothing, you simply need to pattern match on it and give it a name. Instead of
Nothing(_) => // Do something generic
consider
Nothing(n) => // Do something that involves the number n

What's the most idiomatic way of working with an Iterator of Results? [duplicate]

This question already has answers here:
How do I stop iteration and return an error when Iterator::map returns a Result::Err?
(4 answers)
Closed 3 years ago.
I have code like this:
let things = vec![/* ...*/]; // e.g. Vec<String>
things
.map(|thing| {
let a = try!(do_stuff(thing));
Ok(other_stuff(a))
})
.filter(|thing_result| match *thing_result {
Err(e) => true,
Ok(a) => check(a),
})
.map(|thing_result| {
let a = try!(thing_result);
// do stuff
b
})
.collect::<Result<Vec<_>, _>>()
In terms of semantics, I want to stop processing after the first error.
The above code works, but it feels quite cumbersome. Is there a better way? I've looked through the docs for something like filter_if_ok, but I haven't found anything.
I am aware of collect::<Result<Vec<_>, _>>, and it works great. I'm specifically trying to eliminate the following boilerplate:
In the filter's closure, I have to use match on thing_result. I feel like this should just be a one-liner, e.g. .filter_if_ok(|thing| check(a)).
Every time I use map, I have to include an extra statement let a = try!(thing_result); in order to deal with the possibility of an Err. Again, I feel like this could be abstracted away into .map_if_ok(|thing| ...).
Is there another approach I can use to get this level of conciseness, or do I just need to tough it out?
There are lots of ways you could mean this.
If you just want to panic, use .map(|x| x.unwrap()).
If you want all results or a single error, collect into a Result<X<T>>:
let results: Result<Vec<i32>, _> = result_i32_iter.collect();
If you want everything except the errors, use .filter_map(|x| x.ok()) or .flat_map(|x| x).
If you want everything up to the first error, use .scan((), |_, x| x.ok()).
let results: Vec<i32> = result_i32_iter.scan((), |_, x| x.ok());
Note that these operations can be combined with earlier operations in many cases.
Since Rust 1.27, Iterator::try_for_each could be of interest:
An iterator method that applies a fallible function to each item in the iterator, stopping at the first error and returning that error.
This can also be thought of as the fallible form of for_each() or as the stateless version of try_fold().
You can implement these iterators yourself. See how filter and map are implemented in the standard library.
map_ok implementation:
#[derive(Clone)]
pub struct MapOkIterator<I, F> {
iter: I,
f: F,
}
impl<A, B, E, I, F> Iterator for MapOkIterator<I, F>
where
F: FnMut(A) -> B,
I: Iterator<Item = Result<A, E>>,
{
type Item = Result<B, E>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|x| x.map(&mut self.f))
}
}
pub trait MapOkTrait {
fn map_ok<F, A, B, E>(self, func: F) -> MapOkIterator<Self, F>
where
Self: Sized + Iterator<Item = Result<A, E>>,
F: FnMut(A) -> B,
{
MapOkIterator {
iter: self,
f: func,
}
}
}
impl<I, T, E> MapOkTrait for I
where
I: Sized + Iterator<Item = Result<T, E>>,
{
}
filter_ok is almost the same:
#[derive(Clone)]
pub struct FilterOkIterator<I, P> {
iter: I,
predicate: P,
}
impl<I, P, A, E> Iterator for FilterOkIterator<I, P>
where
P: FnMut(&A) -> bool,
I: Iterator<Item = Result<A, E>>,
{
type Item = Result<A, E>;
#[inline]
fn next(&mut self) -> Option<Result<A, E>> {
for x in self.iter.by_ref() {
match x {
Ok(xx) => if (self.predicate)(&xx) {
return Some(Ok(xx));
},
Err(_) => return Some(x),
}
}
None
}
}
pub trait FilterOkTrait {
fn filter_ok<P, A, E>(self, predicate: P) -> FilterOkIterator<Self, P>
where
Self: Sized + Iterator<Item = Result<A, E>>,
P: FnMut(&A) -> bool,
{
FilterOkIterator {
iter: self,
predicate: predicate,
}
}
}
impl<I, T, E> FilterOkTrait for I
where
I: Sized + Iterator<Item = Result<T, E>>,
{
}
Your code may look like this:
["1", "2", "3", "4"]
.iter()
.map(|x| x.parse::<u16>().map(|a| a + 10))
.filter_ok(|x| x % 2 == 0)
.map_ok(|x| x + 100)
.collect::<Result<Vec<_>, std::num::ParseIntError>>()
playground
filter_map can be used to reduce simple cases of mapping then filtering. In your example there is some logic to the filter so I don't think it simplifies things. I don't see any useful functions in the documentation for Result either unfortunately. I think your example is as idiomatic as it could get, but here are some small improvements:
let things = vec![...]; // e.g. Vec<String>
things.iter().map(|thing| {
// The ? operator can be used in place of try! in the nightly version of Rust
let a = do_stuff(thing)?;
Ok(other_stuff(a))
// The closure braces can be removed if the code is a single expression
}).filter(|thing_result| match *thing_result {
Err(e) => true,
Ok(a) => check(a),
}
).map(|thing_result| {
let a = thing_result?;
// do stuff
b
})
The ? operator can be less readable in some cases, so you might not want to use it.
If you are able to change the check function to return Some(x) instead of true, and None instead of false, you can use filter_map:
let bar = things.iter().filter_map(|thing| {
match do_stuff(thing) {
Err(e) => Some(Err(e)),
Ok(a) => {
let x = other_stuff(a);
if check_2(x) {
Some(Ok(x))
} else {
None
}
}
}
}).map(|thing_result| {
let a = try!(thing_result);
// do stuff
b
}).collect::<Result<Vec<_>, _>>();
You can get rid of the let a = try!(thing); by using a match in some cases as well. However, using filter_map here doesn't seem to help.

Resources