Is it possible to wild card the variants of an enum, while still caputing its associated data?
enum BAR {
BAR1,
BAR2,
}
enum BAZ {
BAZ1,
BAZ2,
BAZ3,
}
enum FOO {
FOO1(BAR, BAZ),
FOO2(BAR, BAZ),
FOO3(BAR, BAZ),
//...
}
impl FOO {
pub fn getBar(&self) -> &BAR {
return match self {
FOO::FOO1(bar, _) => bar,
// _(bar, _) => bar,
}
}
}
The enum FOO has over 50 variants. The line FOO::FOO1(bar, _) => bar, does what I need, but it would be quite ugly to list all 50 variants, where all arms essentially look the same. Is there some form of _(bar, _) => bar, where the variants are being wild carded but the associated data is still retrievable?
Is there some form of _(bar, _) => bar, where the variants are being wild carded but the associated data is still retrievable?
No. You can achieve this via a macro, that's about it.
But I've got to say I'm questioning your structure: if you have "over 50 variants" all with exactly the same associated data why is it not a structure with 3 fields?
struct Foo {
discriminant: Whatever,
bar: Baz,
baz: Baz,
}
This is exactly equivalent to what you have on your hands, except it's not a pain in the ass to access bar and baz.
Related
I have a struct in which one of the fields is an enum, and when using a match statement there is a lot of repetition that feels avoidable.
Basically what I have now is
match self.foo // which is an enum, Foo {
Foo::Bar => something,
Foo::Bazz => something else,
_ => you get the point
}
I tried:
match self.foo {
Foo::{
Bar => something,
Bazz => something else,
}
}
but did not have the intended effect. Is it possible to not have to retype Foo:: every time or is it just something I need to live with?
You can use the use Foo::*; statement to bring all the variants of Foo into scope:
enum Foo {
Bar,
Bazz,
}
fn main() {
let foo = Foo::Bar;
use Foo::*;
match foo {
Bar => println!("something"),
Bazz => println!("something else"),
}
}
You can import the names of enum variants to use them directly:
use Foo::*;
match self.foo {
Bar => something,
Bazz => something else,
}
This is how None and Some work without needing Option:: before them.
I'm trying to use a generic datatype where one of the types is not needed (edge weights in a graph). I've been thinking to use the never type for this, which would look something like this:
#![feature(never_type)]
struct Foo<T> {
bar: T
}
impl<T> Foo<T> {
fn foo(&mut self, bar: T) {
self.bar = bar;
}
}
fn main() {
let mut foo: Foo<!> = Foo { bar: "nada" };
foo.foo("nada");
}
This obviously results in a type-mismatch for the "nada" placeholders, but just typing nothing will cause other errors. Is ! the right type to use here, and if so, what's the correct syntax?
I've gotten it to work using () instead of !, but I'm a bit unsure as to whether that's the proper choice of type. I believe in terms of efficiency it should make no difference, as () has no memory footprint?
() is the right choice. It is a type with a single value (also named ()), so it has a value, but contains no information.
! doesn't have any value, so if you put it in a struct the struct type doesn't have a value either and is basically unusable.
For example, if I have code like:
enum Foo {
Bar,
Baz,
Bat,
Quux
}
impl Foo {
from(input: &str) -> Foo {
Foo::input
}
}
This will obviously fail because input is not a method of Foo. I can manually type:
from(input: &str) -> Foo {
match(input) {
"Bar" => Foo::Bar,
// and so on...
}
}
but I'm not getting the automatic convenience.
It looks like Java has a string lookup function on enums for this specific purpose.
Is it possible to get this without writing my own macro or importing one from a crate?
You should implement std::str::FromStr trait.
use std::str::FromStr;
#[derive(Debug, PartialEq)]
enum Foo {
Bar,
Baz,
Bat,
Quux,
}
impl FromStr for Foo {
type Err = ();
fn from_str(input: &str) -> Result<Foo, Self::Err> {
match input {
"Bar" => Ok(Foo::Bar),
"Baz" => Ok(Foo::Baz),
"Bat" => Ok(Foo::Bat),
"Quux" => Ok(Foo::Quux),
_ => Err(()),
}
}
}
fn main() {
// Use it like this
let f = Foo::from_str("Baz").unwrap();
assert_eq!(f, Foo::Baz);
}
Code-generation (aka automatic convenience) and reflections usually bear a cost. In practice, it is unlikely that you will end up with more than a few enum variants.
Run in the playground
Same disclaimer as in other answers: "without macros" isn't possible.
Extending on the highest voted answer. As noted in this thread the combination of custom_derive + enum_derive is somewhat outdated. Modern Rust doesn't need a solution based on custom_derive anymore.
A modern alternative is strum. Usage could look like this:
use strum_macros::EnumString;
use std::str::FromStr;
#[derive(EnumString)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
fn example_usage(input: &str) -> Foo {
Foo::from_str(input).unwrap()
}
Note: You need both strum and strum_macros in your Cargo.toml.
strum also gives some nice flexibility regarding the string representation. From the docs:
Note that the implementation of FromStr by default only matches on the name of the variant. There is an option to match on different case conversions through the #[strum(serialize_all = "snake_case")] type attribute.
Edit: The answer is no. Rust does not provide reflection and usually use #[derive] for that kind of tasks.
You can use the crates enum_derive and custom_derive to do what you want.
Here is an exemple:
#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate enum_derive;
custom_derive! {
#[derive(Debug, EnumFromStr)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
}
fn main() {
let variable: Foo = "Bar".parse().unwrap();
println!("{:?}", variable);
}
the derive of the custom EnumFromStr allows you to use the parse method to get a Foo.
I have some traits which (after removing functions and some parameter bloat) look like:
trait Foo { }
trait Boo { }
trait Bar<T: Foo> { }
trait Baz { }
If U implements Bar<T> for some T implementing Foo and U implements Boo, then one is able to derive an implementation of Baz for U. However, I wasn't able to write valid Rust code doing this.
A few tries were:
impl<T: Foo, U: Bar<T> + Boo> Baz for U { }
which gives
error: the type parameter T is not constrained by the impl trait, self type, or predicates [E0207]
whereas
impl<U: Bar<T> + Boo> Baz for U { }
yields
error: type name T is undefined or not in scope [E0412]
Could one/how could one do this in (stable) Rust (hopefully without any dynamic dispatch)?
Edit: Some people hinted at some similar questions for which there were essentially two approaches (and I find both of them unsuitable for my situation):
Using associated types. I don't want to do this because I want to keep track of T, e.g. I want to write some functions which have a signature like fn bla<T: Foo, U: Bar<T>, V: Bar<T>>() where I want to know that U and V implement Bar<T> for the same T. (Or is there way of doing this with associated types?)
Using some kind of wrapping by putting U and T in a struct. I don't want to use this either because I have several levels of such "trait dependencies", so wrapping things in each level would bloat the code a lot.
So the updated question would be: Is there a solution to this problem without using associated types or wrappers?
You can do it making T an associated type:
trait Foo { }
trait Boo { }
trait Bar {
type T: Foo;
}
trait Baz { }
impl<U: Bar + Boo> Baz for U
// this where clause is not necessary (this bound is already true)
// where U::T: Foo
{ }
I don't want to do this because I want to keep track of T, e.g. I want to write some functions which have a signature like fn bla<T: Foo, U: Bar<T>, V: Bar<T>>() where I want to know that U and V implement Bar<T> for the same T. (Or is there way of doing this with associated types?)
Yes, you can do it with associated types:
fn bla<U: Bar, V: Bar<T = U::T>>() { }
Is there a way to extract the tag of an enum to, e.g., use it as an index?
I'd like to have a vector of vectors classified by enum type, i.e., if I had:
enum Test {
Point {
x: i32,
y: i32,
},
Point2 {
a: i32,
b: i32,
},
Number(i32),
}
I may want a vector like this:
[[Test::Point{1, 2}, Test::Point{3, 4}], [Test::Number(1), Test::Number(2)]]
I'd like to dynamically add to this vector of vectors given new values. So if a function was passed in a Test::Number, it would go in the second array.
Certainly in the worst case I could explicitly pattern match every possible union value, but for large enums that would get rather verbose and repetitive since all the cases would just end up as
match e {
Test::Point { _, _ } => v[0].push(e),
Test::Point2 { _, _ } => v[1].push(e),
Test::Number(_) => v[2].push(e),
// imagine a lot of these
}
I've tried a lot of syntax permutations, but I haven't gotten anything that will compile. Is there a way to treat the enum struct tags like, well, an enumeration? It looks like there's a FromPrimitive derive, but it's unstable and doesn't work on struct enums.
(I suppose an alternative question if you can't is if you can write a macro to autowrite that match).
You can use .. to ignore all fields of an enum, no matter how many there are, and you can import variants from inside the enums namespace with use. E.g
enum Foo {
X { i: u8 },
Y(u8),
Z
}
fn bar(x: Foo) -> u32 {
use Foo::*;
match x {
X { .. } => 100,
Y(..) => 3,
Z => 12,
}
}
You can use the alternation syntax (via |) in the match arms and methods on the enum to reduce code duplication:
enum Test {
Point1,
Point2,
Point3,
Point4,
Number1,
Number2,
Number3,
Number4,
}
impl Test {
fn bucket(&self) -> u8 {
use Test::*;
match *self {
Point1 | Point2 | Point3 | Point4 => 0,
Number1 | Number2 | Number3 | Number4 => 1,
}
}
}