Imagine that you want a way to remove fields at compile time depending on generic parameters. You can do this:
struct MyStruct<T, const B: usize>
{
optional: [T; B]
}
If B = 0 then the array is of size 0, effectively removing it.
The only problem I have with this is that I want B to only ever be either 0 or 1 and I would like some nicer syntax to access the field than
var.optional[0]
I am wondering if there's a better way of achieving the exact same thing.
You can use a helper trait and its associated type to conditionally change the field type to ():
pub struct MyStruct<T, const B: bool>
where
Self: private::Sealed,
{
optional: <Self as private::Sealed>::Optional,
}
mod private {
pub trait Sealed {
type Optional;
}
}
impl<T> private::Sealed for MyStruct<T, true> {
type Optional = T;
}
impl<T> private::Sealed for MyStruct<T, false> {
type Optional = ();
}
pub fn present(v: MyStruct<i64, true>) -> i64 {
v.optional
}
pub fn absent(v: MyStruct<i64, false>) -> () {
v.optional
}
Playground
The caveat is that, the struct now has a trait bound, so you cannot use it generically without copying the bound to the call site:
pub fn generic<const B: bool>(v: MyStruct<i64, B>) {
//~^ERROR the trait bound `MyStruct<i64, B>: Sealed<i64>` is not satisfied
dbg!(v.optional);
}
You can use it generically if you expose the helper types as public API, but that won't be quite ergonomic:
pub fn generic<const B: bool>(v: MyStruct<i64, B>)
where
MyStruct<i64, B>: private::Sealed<Optional: core::fmt::Debug>,
{
dbg!(v.optional);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With