Const arguments cannot yet be inferred with `_`

I have struct

pub struct A<B, const C: u8> {
    pub _a: PhantomData<B>,
}

impl<B, const C: u8> A<B, C> {
    pub(crate) fn new() -> Self {
        Self {
            _a: core::marker::PhantomData,
        }
    }
}

I want to wrap it with my struct and create array from it

pub struct MyA<B, const C: u8> {
    pub a: A<B, C>,
}

type B1 = u8;
type B2 = u8;

fn main() {

  let _arr: [MyA<_,_>; 4] = [
  MyA{a: A::<B1,1>::new()},
  MyA{a: A::<B1,2>::new()},
  MyA{a: A::<B2,1>::new()},
  MyA{a: A::<B2,2>::new()},
  ];
  
}

And I get an error

error[E0747]: type provided when a constant was expected
 --> src/main.rs:8:20
  |
8 |   let _arr: [MyA<_,_>; 4] = [
  |                    ^
  |
  = help: const arguments cannot yet be inferred with `_`

Is there some way to combine such structures into an array?

Playground

>Solution :

This has nothing to do with const argument inference. There is no valid type to infer here. The mechanism of inference is the compiler finding the explicit type to put instead of you; there still has to be an explicit type that you might’ve written by hand for that works for the compiler to find.1

Arrays in Rust are homogenous, so each element has to have the same type. To fit MyA{a: A::<B1,1>::new()}, it has to be MyA<u8, 1>. But to fit MyA{a: A::<B1,2>::new()} it has to be MyA<u8, 2>. So it can be neither. Both of these fail to compile:

let _arr: [MyA<_,1>; 4] = [
    MyA{a: A::<B1,1>::new()},
    MyA{a: A::<B1,2>::new()}, // error[E0308]: mismatched types, expected A<_,1>, found A<_,2>
    MyA{a: A::<B2,1>::new()},
    MyA{a: A::<B2,2>::new()}, // error[E0308]: mismatched types, expected A<_,1>, found A<_,2>
];
let _arr: [MyA<_,2>; 4] = [
    MyA{a: A::<B1,1>::new()}, // error[E0308]: mismatched types, expected A<_,2>, found A<_,1>
    MyA{a: A::<B1,2>::new()},
    MyA{a: A::<B2,1>::new()}, // error[E0308]: mismatched types, expected A<_,2>, found A<_,1>
    MyA{a: A::<B2,2>::new()}, 
];

The key here is that A<B, 1> and A<B, 2> are completely different types. The compiler will not allow you to assign values of one to the other without some manual conversion.

There’s a number of things you can do to work around this, and the best one will depend on what you’re trying to actually achieve with that array.

Enum

The direct Rusty thing to do would be to wrap the elements in an enum and have an array of those:

pub enum MyAEnum<B> {
    C1(MyA<B, 1>),
    C2(MyA<B, 2>),
}

fn main() {
  let _arr: [MyAEnum<_>; 4] = [
      MyAEnum::C1(MyA{a: A::<B1,1>::new()}),
      MyAEnum::C2(MyA{a: A::<B1,2>::new()}),
      MyAEnum::C1(MyA{a: A::<B2,1>::new()}),
      MyAEnum::C2(MyA{a: A::<B2,2>::new()}),
  ];
}

You can then pass this around and match on the variant before use.

dyn trait

Another one would be to encapsulate the behaviour of your struct in a trait, and box it as an object type.

pub trait MyATrait<B> { }

impl<B, const C: u8> MyATrait<B> for MyA<B, C> { }

fn main() {
  let _arr: [Box<dyn MyATrait<_>>; 4] = [
      Box::new(MyA{a: A::<B1,1>::new()}),
      Box::new(MyA{a: A::<B1,2>::new()}),
      Box::new(MyA{a: A::<B2,1>::new()}),
      Box::new(MyA{a: A::<B2,2>::new()}),
  ];
}

You can pass this around and then interact with the values via the trait.


  1. Barring cases where a type might be unspeakable. For example, you can’t write the concrete types of closures by hand. But for this question’s purposes that statement is sufficient.

Leave a Reply