Returning value of enum [duplicate] - rust

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

Related

How can I get enum value by its name? [duplicate]

This question already has answers here:
Can I convert a string to enum without macros in Rust?
(3 answers)
Closed 12 months ago.
I know how to do it in Java.
It seems I need to implement TryFrom or something like that.
enum ROMAN {
I = 1,
V = 5,
X = 10,
L = 50,
C = 100,
D = 500,
M = 1000
}
I want to get value using by enums name.
println!("{:?}", ROMAN::valueOf("M")); // It should be `1000`
Either implement FromStr or TryFrom manually, or use something like enum_derive which provides these features.
Or just add a bespoke value_of method on your enum without bothering with traits.
Or do all of it, though that seems a bit much
impl Roman {
pub fn value_of(s: &str) -> Option<Self> {
Some(match s {
"I" => Self::I,
"V" => Self::V,
"X" => Self::X,
"L" => Self::L,
"C" => Self::C,
"D" => Self::D,
"M" => Self::M,
_ => return None,
})
}
}
impl FromStr for Roman {
type Err = (); // should probably provide something more useful
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::value_of(s).ok_or(())
}
}
impl TryFrom<&str> for Roman {
type Error = ();
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::value_of(s).ok_or(())
}
}
println!("{:?}", ROMAN::valueOf("M")); // It should be `1000`
It's never going to be 1000 because that's not how Rust works. You'd need to handle the error then convert the success value to its discriminant.

Match on pair of enum when both are of the same kind

I want to get rid of the repeated code here, and not have to list each enum kind:
use Geometry::*;
let geometry = match (&self.geometry, &other.geometry) {
(Point(a), Point(b)) => Point(*a.interpolate(b, t)),
(Curve(a), Curve(b)) => Curve(*a.interpolate(b, t)),
(EPBox(a), EPBox(b)) => EPBox(*a.interpolate(b, t)),
(_, _) => unimplemented!("Kinds not matching")
};
The types inside the kinds all implement the Interpolate trait which has the interpolate method:
enum Geometry {
Point(Point),
Curve(Curve),
EPBox(EPBox)
}
trait Interpolate {
fn interpolate(&self, other: &Self, t: f64) -> Box<Self> {
// ...
}
}
impl Interpolate for Point {}
impl Interpolate for Curve {}
impl Interpolate for EPBox {}
What I want to do is something like this:
let geometry = match (&self.geometry, &other.geometry) {
(x(a), x(b)) => x(*a.interpolate(b, t)), // and check that a and b impls Interpolate
(_, _) => unimplemented!("Kinds not matching")
};
I'm not sure how many of these operations you want to implement, and how many enum variants you actually have. Depending on that, the best answer changes quite a bit, I think. If you really only have one operation (interpolate), and three variants: type it out, anything else will be a lot less simple and maintainable.
That being said, I might use
let geometry = binop!(match (&self.geometry, &other.geometry) {
(a, b) => *a.interpolate(b, t)
});
based on
macro_rules! binop {
(match ($av:expr, $bv:expr) { ($a:ident, $b:ident) => $op:expr }) => {{
use Geometry::*;
binop!($av, $bv, $a, $b, $op, Point, Curve, EPBox)
}};
($av:expr, $bv:expr, $a:ident, $b:ident, $op:expr, $($var:path),*) => {
match ($av, $bv) {
$(($var($a), $var($b)) => $var($op),)*
_ => unimplemented!("Kinds not matching")
}
};
}
Playground
You'll have to list up the enum variants once. If you don't want that, you'll have to go for a proc macro. I think that would be overkill.
With your current code, you can't really do this. Checking if the enum variants are the same variant is fairly simple with the use of core::mem::discriminant, but you can't access the contained value without match or if let statements. What you can do is use type parameters for the variables and type IDs. This is a really tacky way to do things, and should be avoided really, but it works. I've given an example to show you how you could implement it
use std::any::Any;
trait SomeTrait {
fn some_function(&self, other: Self) -> &Self;
}
#[derive(Clone)]
struct Var0 {
eg: i64
}
#[derive(Clone)]
struct Var1 {
other_eg: f64
}
fn check<T: 'static, B: 'static>(lhs: T, rhs: B) -> Option<T> {
if lhs.type_id() == rhs.type_id() {
Some(lhs.some_function(rhs))
} else {
None
}
}
fn main() {
let a = Var0{ eg: 2 };
let b = Var0{ eg: 9 };
let c = Var1 { other_eg: -3f64 };
assert!(check(a.clone(), b).is_some());
assert!(check(a, c).is_none());
}
impl SomeTrait for Var0 { /* ... */ }
impl SomeTrait for Var1 { /* ... */ }
Please note though: as I said before this is messy and pretty hacky and not very nice to read. If I were writing this I would use the match statement over this, but it's up to you what you do since this does require some reworking to implement. I'm also not sure if you can use different lifetimes for the check function other than `static which might be a problem.
I came up with the following solution, which is easy to extend with new Interpolate types:
macro_rules! geometries {
( $( $x:ident ),+ ) => {
enum Geometry {
$(
$x($x),
)*
}
fn interpolate_geometries(a: &Geometry, b: &Geometry, t: f64) -> Geometry {
use Geometry::*;
match (a, b) {
$(
($x(a), $x(b)) => $x(a.interpolate(b, t)),
)*
_ => unimplemented!("Kinds not matching")
}
}
$(
impl Interpolate for $x {}
)*
};
}
geometries!(Point, Curve, EPBox);
Which make it possible to later do:
let geometry = interpolate_geometries(&self.geometry, &other.geometry, t);
Thanks for all answers and comments! Especially the one with the binop macro, which is quite similar to my solution. After reading up on macros (thanks to comments here) I came up with this solution.

Unwrap Result inside Optional [duplicate]

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.

How do I collect from multiple iterator types?

I am attempting to implement a new trait for a String that has a function that capitalizes the first letter of each String and un-capitalizes the rest. I am basing the function's interface on to_uppercase() and to_lowercase() in the Rust Standard Library.
use std::io;
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
self.chars().enumerate().map(|(i, c)| {
match i {
0 => c.to_uppercase(),
_ => c.to_lowercase(),
}
}).collect()
}
}
fn main() {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).ok().expect("Unable to read from stdin.");
println!("{}", buffer.to_capitalized());
}
This code is based on a suggestion given here, but the code is outdated and causes multiple compilation errors. The only issue I am having with my implementation now is the following error:
src/main.rs:10:13: 13:14 error: match arms have incompatible types [E0308]
src/main.rs:10 match i {
^
src/main.rs:10:13: 13:14 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:10:13: 13:14 note: expected type `std::char::ToUppercase`
src/main.rs:10:13: 13:14 note: found type `std::char::ToLowercase`
src/main.rs:12:22: 12:38 note: match arm with an incompatible type
src/main.rs:12 _ => c.to_lowercase(),
So in short, the return values of fn to_uppercase(&self) -> ToUppercase and fn to_lowercase(&self) -> ToLowercase can't be collected together because the map now has multiple return types.
I've attempted trying to cast them to another common Iterator type such as Bytes and Chars, but these iterator types can't be collected to form a String. Any suggestions?
Casting is rarely a good approach to solving type issues in Rust. The correct solution here would be to write (or find a crate that defines) a type that unifies disparate iterator types. But that would require effort, so it's simpler to just throw collect out the window:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
let mut r = String::with_capacity(self.len());
for (i, c) in self.chars().enumerate() {
match i {
0 => r.extend(c.to_uppercase()),
_ => r.extend(c.to_lowercase()),
}
}
r
}
}
fn main() {
let buffer = String::from("canberra");
println!("{}", buffer.to_capitalized());
}
This is, more or less, what collect would do anyway if you had some type to represent "either ToUppercase or ToLowercase". In the vast majority of cases, this will also only perform a single allocation.
Here's how I would do it:
trait ToCapitalized {
fn to_capitalized(&self) -> String;
}
impl ToCapitalized for String {
fn to_capitalized(&self) -> String {
match self.chars().next() {
Some(c) => {
c.to_uppercase()
.chain(self.chars().skip(1).flat_map(|c| c.to_lowercase()))
.collect()
}
None => String::new(),
}
}
}
fn main() {
println!("{}", "fOoBaR".to_string().to_capitalized());
}
This will be a little slower than the ideal solution, as it decodes the first char twice, but it's quite readable IMO.
Output:
Foobar
After looking at the implementation for pub fn to_uppercase(&self) -> String here, I devised a solution that is a bit of a hybrid between Dogbert and DK.'s solutions and the implementation given in the standard library. It even works with Unicode!
fn to_capitalized(&self) -> String {
match self.len() {
0 => String::new(),
_ => {
let mut s = String::with_capacity(self.len());
s.extend(self.chars().next().unwrap().to_uppercase());
s.extend(self.chars().skip(1).flat_map(|c| c.to_lowercase()));
return s;
}
}
}
Working Rust Playground Example
Edit: For greater visibility, Shepmaster's simplified and optimized solution:
fn to_capitalized(&self) -> String {
let mut s = String::with_capacity(self.len());
let mut chars = self.chars();
s.extend(chars.by_ref().take(1).flat_map(|c| c.to_uppercase()));
s.extend(chars.flat_map(|c| c.to_lowercase()));
s
}

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