And a vector of Item: items: Vec<Item>
I want to know if there's any item which is Foo, no matter what value it has, I write like this:
fn has_foo(items: &[Item]) -> bool {
for item in items {
if let Foo(_) = item {
return true;
}
}
return false;
}
And now comes the questions: What if I want to check an arbitrary variant? I guess the match pattern is something that only exist on compile time, so the function may look like this:
fn has<Item::XX/*I don't know how to write this*/>(pattern:XX, items: &[Item]) -> bool
So I can use the function like:
let res = has(Item::Foo, items);
It looks to me that the only option is to use macros, but I wondered if there are other ways.
A pattern is not a type, so no. But you can accept a closure that returns true if a specific item matches, and you can turn a match into a boolean directly using the matches!macro.
Also note that your loop is essentialy Iterator::any():
IIRC, there's a function in std that can turn an enum variant to some sort of numeric representation, but I forget the name of that function and can't find it again, do you happen to know that?
It can't, that's instant undefined behavior. You could use a sensible, cheap-to-construct value instead, such as 0 or String::new() (for Item::Bar) or in general Default::default().
I'm talking about a more generic situation, in which not all types are implemented Default, even more, you may not able to create a instance of a certain type. In this case, I cannot offer a
d: Discriminant<Item>
without using MaybeUninit. And I think it is safe, because in this case, I don't realy read any value from the variant, I just use the Discriminant for comparing, right? Please correct me if I wrong.
Don't use MaybeUninit::uninit().assume_init() for a type you don't know it's safe to be fully uninitialized, there's very few of those, mostly types composed entirely of MaybeUninit, certainly no enums,
I strongly favor the "pass a closure to match against the variant" approach,
with deriving a mirror of the enum without.fields (usually with a Kind suffix) as the other approach.
I'm not creating an enum with MaybeUninit, I'm creating, for example, an Item::Foo(MaybeUninit), and use it to compare with other Item::Foo(_)s, by using Discriminant.
Even in this case, An Item::Foo(MaybeUninit) can still have a chance to mess up Discriminant, right?
As you can see in the example in my previous message, leaving fields uninitialized can change the variant.
(I'm still ignoring UB for the moment, you shouldn't use uninitialized memory for this at all)
I understood what you were talking about. Foo(MaybeUninit::uninit().assume_init())is undefined behavior. It doesn't matter what kind of type you are instantiating in this way: if it's an enum, a struct, a primitive integer, etc. – if you lie to the compiler about the value being initialized, it is always and unconditionally UB. (The only exception is when the type is MaybeUninit itself or a composite type only consisting of MaybeUninits, but that is not the case here.)