A pattern matching against a constructor of an enum - rust

I have an enum:
pub enum Enum1 {
A(String),
B(i64),
C(f64)
}
How can I do pattern matching against A? That is, I want to get its String value. I've tried this:
match optionMyEnum {
Some(A(x: String)) => ...
and got plenty of the compile errors.

The Rust Programming Language has an entire section on matching. I'd highly encourage you to read that section (and the entire book). A lot of time and effort has gone into that documentation.
You simply specify a name to bind against. There's no need to write out types:
pub enum Enum {
A(String),
B(i64),
C(f64),
}
fn main() {
let val = Enum::A("hello".to_string());
match val {
Enum::A(x) => println!("{}", x),
_ => println!("other"),
}
}
In many cases, you will want to bind to a reference to the values:
Enum::A(ref x) => println!("{}", x),

Related

How do I implement From<T> for Option<U> in Rust?

Assuming I have an enum as:
enum Foo {
A,
B,
}
...where I want to implement something like this:
impl From<char> for Option<Foo> {
fn from(chr: char) -> Self {
match chr {
'A' => Some(Foo::A),
'B' => Some(Foo::B),
_ => None,
}
}
}
This is currently illegal since Option is out of my own crate, it is owned by std. The compiler error is:
only traits defined in the current crate can be implemented for types defined outside of the crate
define and implement a trait or new type instead rustc(E0117)
As in the case I have shown above, in some cases, I'd like to have None instead of Some. Is there a way to implement a From that I am able to get Option<U> instead of U itself?
Environment
Rust 1.62.1
I think what you actually want in this scenario is to implement the TryFrom trait instead.
For example (ideally you'd make a proper Error type rather than a str):
impl TryFrom<char> for Foo {
type Error = &'static str;
fn try_from(chr: char) -> Result<Foo, Self::Error> {
match chr {
'A' => Ok(Foo::A),
'B' => Ok(Foo::B),
_ => Err("can't convert character to Foo"),
}
}
}

Perform checks on a nested enum

I have an enum which is defined as follows:
enum MyEnum {
X(u32),
Y(Vec<MyEnum>),
Z(Vec<MyEnum>),
}
As you can see, the enum is nested and can have other enums of its type inside of it. I'm trying to perform a simple check: I want to check if any of the u32s is greater than 5.
I have thought about using recursion here as this seems like an inherently recursive problem but from my searches it was clear that rust doesn't support recursion or that it is not recommended that it is used. How would I go about solving this problem and performing the check?
You can make a method over your Enum, and recursively call it:
enum MyEnum {
X(u32),
Y(Vec<MyEnum>),
Z(Vec<MyEnum>),
}
impl MyEnum {
fn greater_than(&self, x: u32) -> bool {
match self {
Self::X(v) => v > &x,
Self::Y(v) | Self::Z(v) => v.iter().any(|y| y.greater_than(x)),
}
}
}
Playground
It is perfectly ok to use recursion in Rust, there is no particular problem about it.
In your case, you could write your check like this:
fn my_check(en: &MyEnum) -> bool {
match en {
MyEnum::X(n) => *n > 5,
MyEnum::Y(v) | MyEnum::Z(v) => v.iter().any(my_check),
}
}

How to access an enum variant's field without explicitly binding it during match?

Lets say I have an enum E, that might be auto-generated or outside of my control, with many variants and each variant having a number of fields.
enum E {
A {
x1: u8,
x2: u8,
x3: u8,
// ...
x9: u8,
},
B,
}
In reality the fields might be longer and neither nice to remember, nor nice to type.
I now want to write functions that operate on (variants of) E. However, I am also lazy, and I don't want to repeat myself, declaring each used field explicitly when destructuring the enum*.
Intuitively I would have expected the binding operator # to do the job here, but it only binds the whole enum e, not the given variant E::A.
What is the shortest / most elegant way to achieve the following intention?
fn f(e: &E) {
match e {
bad # E::A { .. } => dbg!(bad.x1),
_ => {}
}
}
*Update since this has been brought up in two answers already, I do not want to match with E::A { x1, .. }, as this gets tedious when needing multiple fields with long names. In the example below, I would have to type out some_other_field_with_an_impossibly_long_name twice in my own code (once when binding it, once when using it), whereas in the hypothetical bad # E::A case I'd have to type it out only once.
match e {
E::A { some_field_with_a_long_name, some_other_field_with_an_impossibly_long_name, yet_another_field, .. } => dbg!(some_other_field_with_an_impossibly_long_name),
_ => {}
}
I think the following could help:
fn f(e: &E) {
match e {
E::A {x1, .. } => {dbg!(x1);},
_ => {}
};
}
E::A {x1,..} is short for bad # E::A {x1:x1, ..} and binds the value of bad.x1 to a new local variable x1 that is available in the body scope.
You may use a macro with variadic args, so the compiler does the typing long names twice, and it binds as many as parameters you need. You may call your function inside the macro instead of println:
f!(&e, x1);
f!(&e, x2, x1);
macro_rules! f {
($e: expr, $( $name:ident ),+ ) => {
match $e {
E::A { $($name),* , ..} => {
println!("{:?}", &[$($name),*]); // call your function here.
}
_ => {}
}
};
}
Try it on the Rust Playground

Is there a shorter way than a match or if let to get data through many nested levels without increasing the total amount of code?

I work with a bunch of structs / enums included in each other. I need to get ty.node<TyKind::Path>.1.segments.last().identifiers and ty.node<TyKind::Path>.1.segments.last().parameters<AngleBracketed::AngleBracketed>.types.
Is there a simpler way to get these two values then my implementation of f? My ideal syntax would be:
ty.node<TyKind::Path>?.1.segments.last().identifiers
// and
ty.node<TyKind::Path>?.1.segments.last().parameters<AngleBracketed::AngleBracketed>?.types
It that's impossible, maybe there is a way to reduce the number of if let? I want to solve only this particular case, so simplification should be possible compared to f. If an analog of Option::map / Option::unwrap_or_else were introduced, then the sum of its code + the code in f should be less then my original f.
#[derive(Clone)]
struct Ty {
node: TyKind,
}
#[derive(Clone)]
enum TyKind {
Path(Option<i32>, Path),
}
#[derive(Clone)]
struct Path {
segments: Vec<PathSegment>,
}
#[derive(Clone)]
struct PathSegment {
identifier: String,
parameters: Option<Box<PathParameters>>,
}
#[derive(Clone)]
enum PathParameters {
AngleBracketed(AngleBracketedParameterData),
}
#[derive(Clone)]
struct AngleBracketedParameterData {
types: Vec<Box<Ty>>,
}
/// If Tylnode == Path -> return last path segment + types
fn f(ty: &Ty) -> Option<(String, Vec<Box<Ty>>)> {
match ty.node {
TyKind::Path(_, ref path) => if let Some(seg) = path.segments.iter().last() {
let ident = seg.identifier.clone();
println!("next_ty: seg.id {:?}", seg.identifier);
match seg.parameters.as_ref() {
Some(params) => match **params {
PathParameters::AngleBracketed(ref params) => {
Some((ident, params.types.clone()))
}
_ => Some((ident, vec![])),
},
None => Some((ident, vec![])),
}
} else {
None
},
_ => None,
}
}
To simplify the question, I have removed unrelated enum variants and struct fields.
No.
The closest you can get, using nightly features and helper code, is probably this
fn f(ty: &Ty) -> MyOption<(String, Vec<Box<Ty>>)> {
let last = ty.node.path()?.segments.my_last()?;
Just((
last.identifier.clone(),
last.ab_parameters()
.map(|v| v.types.clone())
.unwrap_or_else(|| vec![]),
))
}
Playground
I guess what you want is called Lenses. Not sure about Rust, but here is about Haskell https://en.m.wikibooks.org/wiki/Haskell/Lenses_and_functional_references
It might be possible to implement that in Rust, if somebody haven't done yet.

Accessing tuple from within an enum

I have a Rust enum defined like this
enum MyFirstEnum {
TupleType(f32, i8, String),
StuctType {varone: i32, vartwo: f64},
NewTypeTuple(i32),
SomeVarName
}
I have the following code:
let mfe: MyFirstEnum = MyFirstEnum::TupleType(3.14, 1, "Hello".to_string());
I'm following the Rust documentation and this looks fine. I don't need to define everything in the enum, but how would I go about accessing the mid element in the enum tuple?
mfe.TupleType.1 and mfe.1 don't work when I add them to a println!
I know Rust provides the facility to do pattern matching to obtain the value, but if I changed the code to define the other variants within the enum, the code to output a particular variant would quickly become a mess.
Is there a simple way to output the variant of the tuple (or any other variant) in the enum?
This is a common misconception: enum variants are not their own types (at least in Rust 1.9). Therefore when you create a variable like this:
let value = MyFirstEnum::TupleType(3.14, 1, "Hello".to_string());
The fact that it's a specific variant is immediately "lost". You will need to pattern match to prevent accessing the enum as the wrong variant. You may prefer to use an if let statement instead of a match:
if let MyFirstEnum::TupleType(f, i, s) = value {
// Values available here
println!("f: {:?}", f);
}
Example solution:
enum MyFirstEnum {
TupleType(f32, i8, String),
// StuctType { varone: i32, vartwo: f64 },
// NewTypeTuple(i32),
// SomeVarName,
}
fn main() {
let mfe: MyFirstEnum = MyFirstEnum::TupleType(3.14, 1, "Hello".to_string());
let MyFirstEnum::TupleType(value, id, text) = &mfe;
println!("[{}; {}; {}]", value, id, text);
//or
match &mfe {
MyFirstEnum::TupleType(value, id, text) => {
println!("[{}; {}; {}]", value, id, text);
}
// _ => {}
}
}
Playground link

Resources