Jesper
October 2, 2023, 6:23pm
1
I want to index an array with an enum - with enum of primitives the Index trait can be implemented like so:
enum Obj {
Gold=0,
Silver,
Emerald
}
const N_OBJECTS: usize = Obj::Emerald as usize + 1;
impl<T> Index<Obj> for [T; N_OBJECTS] {
type Output = T;
fn index(&self, idx: Obj) -> &Self::Output {
&self[idx as usize]
}
}
impl<T> IndexMut<Obj> for [T; N_OBJECTS] {
fn index_mut(&mut self, idx: Obj) -> &mut Self::Output {
&mut self[idx as usize]
}
}
let a: [bool; N_OBJECTS] = [true; N_OBJECTS];
println!("{:?}", a[Obj::Gold]);
How to do this if some of the enum variants are not not primitive? (In this case it would be ok to only have one index value for Emerald(u8)).
enum Obj {
Gold=0,
Silver=1,
Emerald(u8),
}
H2CO3
October 2, 2023, 6:36pm
2
You could create a derive macro that implements a trait for getting a variant index by matching on &self
.
1 Like
You could also create another fieldless enum
with the same variant names, if this is something you want to store in a typed fashion. There exists crates that can do this for you.
2 Likes
Here's another popular crate that does this for enums whose variants are all primitives: enum_map
And yeah, you won't be able to index on a non-primitive, but you could define a mapping function to a separate enum to use this way.
1 Like
I feel like everyone is overcomplicating things with derive macros and so on. What's wrong with a match
statement?
use std::ops::Index;
enum Obj {
Gold,
Silver,
Emerald(u8),
}
impl<T> Index<Obj> for [T] {
type Output = T;
fn index(&self, idx: Obj) -> &Self::Output {
match idx {
Obj::Gold => &self[0],
Obj::Silver => &self[1],
Obj::Emerald(index) => &self[index as usize],
}
}
}
(playground)
2 Likes
Jesper
October 4, 2023, 9:36am
6
Many thanks - I like this solution in general.
In the actual problem I have reverted to primitive enums.
There are about 100 variants and I don't like to list them individually a 2nd time.
The external crate solutions make it easier to do without bloating the visible source, but don't like to resort to an external crate for a core language issue like this. Also, it is not without cost.
H2CO3
October 4, 2023, 12:34pm
7
What's wrong with it is that you now have to maintain the types at two places, and risk introducing a bug if you forget to update the match if eg. you swap the order of two variants.
A derive-based solution would automatically eliminate this sort of logic error.