I'd like to use a const
usize
value associated with a trait to size an array that is also associated with the trait. Unfortunately you cannot perform a const
operation using Self
, such as:
enum SomeEnum { A, B, C, D, E, F }
trait OriginalGoal {
const SIZE: usize;
const DESIRED_ARRAY: [SomeEnum; Self::SIZE];
}
But I have found a workaround using nightly and generic const expressions, though it must be split between two separate traits otherwise the compiler can't reason past the circular dependency...
#![feature(generic_const_exprs)]
trait ArraySize {
const SIZE: usize;
}
trait DesiredTrait: ArraySize
where
[SomeEnum; <Self as ArraySize>::SIZE]: Sized,
{
const DESIRED_ARRAY: [SomeEnum; <Self as ArraySize>::SIZE];
}
This doesn't actually lead to terrible implementations, but the setup is still a bit rough.
struct Test {}
impl ArraySize for Test {
const SIZE: usize = 3;
}
impl DesiredTrait for Test {
const DESIRED_ARRAY: [SomeEnum; <Self as ArraySize>::SIZE] = {
[SomeEnum::A, SomeEnum::B, SomeEnum::F]
};
}
And a playground link, just to show it working.
I realize I'm just eliminating an associated type by switching to const
generics: other playground. But I'm seeing the const generic option as directly allowing methods to return same-sized arrays of other types without defining extra types, as well as being able to define type aliases that rely on said const
value:
trait GetFloat: DesiredTrait
where
[f64; <Self as ArraySize>::SIZE]: Sized,
{
fn get_float(&self) -> [f64; <Self as ArraySize>::SIZE];
}
type AssociatedArray<D: ArraySize> = [(); <D as ArraySize>::SIZE];
And yet, I wonder if I'm just adding complication for minimal benefit or to get options which I could make work in other ways using associated types.
Does anyone have any thoughts on pros/cons of either method?