Reputation: 4319
I have an enum in Rust like:
enum List {
Rather,
Long,
List,
Of,
Items,
}
And I have a &str which can look like:
let a = "InMyList"
let b = "InMyRather"
let c = "NotContain"
Is there an efficinet way of doing a.contains(List)
?
I can go through each enum item and do a.contains(List::Rather) || a.contains(List::Long)
etc. But if the list is long enough, that's a lot of boilerplate code!
Upvotes: 0
Views: 1276
Reputation: 11708
As you said:
I can go through each enum item and do a.contains(List::Rather) || a.contains(List::Long) etc. But if the list is long enough, that's a lot of boilerplate code!
So in order to avoid typing many "OR"-checks, which is not only tedious but also error prone, you simply need a way to loop through all the enum variants. Please take a look at the strum crate and also this discussion.
Note: If optimal performance is your goal, regex can be a faster solution than simply looping over the enum variants. Please see Todd's answer and the comments that follow it.
Upvotes: 2
Reputation: 5395
It'll be more efficient to do the string matching with a regular expression than iterating over each variant name and trying to find it as a substring in the target strings. I put together an example of how this can be done using the strum
and regex
crates.
The enum with a long list of variants, and a set of target strings to search.
use std::str::FromStr;
use lazy_static::lazy_static;
use regex::Regex;
use strum::{EnumString, EnumVariantNames, VariantNames};
#[derive(EnumString, EnumVariantNames, Debug)]
enum Thing {
Foo,
Bar,
Baz,
Qux,
Quux,
Quuz,
Corge,
Grault,
Garply,
Waldo,
Fred,
Plugh,
Xyzzy,
Thud,
}
// Target strings to look for variant names in.
//
static STRINGS: [&str; 10] = [
"fdskQuuzjfkds", "fkjdFoo", "Fred", "fkdXyzzy", "Plughfkdjs",
"QuuxQuux", "GraultGarply", "TTTThud", "CCorgee", "Waldo",
];
Setting up the regular expression as a static that only needs to be compiled once at runtime. It's constructed from the names of the variants as provided by the strum
crate's feature.
lazy_static! {
// A Regular Expression used to find variant names in target strings.
//
static ref THING_EXPR: Regex = {
// Piece together the expression from Thing's variant names.
let expr_str = Thing::VARIANTS.join("|");
Regex::new(&expr_str).unwrap()
};
}
Example code showing how the set of strings can be iterated over and variants detected and handled. The variant name is first captured then extracted from the expression result, then the enum's variant of the same name is retrieved using the string.
fn main() {
for target in STRINGS {
if let Some(captures) = THING_EXPR.captures(target) {
// Get the substring that matched one of the variants.
let variant_name = &captures[0];
// Convert the string to the actual variant.
let variant = Thing::from_str(variant_name).unwrap();
println!("variant name: {:<8} -- variant: {:?}",
variant_name, variant);
}
}
}
Add these dependencies to the Cargo.toml file:
[dependencies]
lazy_static = "1.4"
strum = { version = "0.21", features = ["derive"] }
regex = "1.5"
output:
variant name: Quuz -- variant: Quuz
variant name: Foo -- variant: Foo
variant name: Fred -- variant: Fred
variant name: Xyzzy -- variant: Xyzzy
variant name: Plugh -- variant: Plugh
variant name: Quux -- variant: Quux
variant name: Grault -- variant: Grault
variant name: Thud -- variant: Thud
variant name: Corge -- variant: Corge
variant name: Waldo -- variant: Waldo
Upvotes: 2