Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const expression optional fields

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.

like image 807
Makogan Avatar asked Jul 26 '26 02:07

Makogan


1 Answers

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);
}
like image 119
tesaguri Avatar answered Jul 28 '26 01:07

tesaguri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!