Consider the classic example of a const-generic datastructure: a square matrix.
struct Matrix<T, const N: usize> {
inner: [[T; N]; N]
}
I'd like to return a structure whose const parameter is dynamically defined:
fn read_matrix() -> ??? {
let n: usize = todo!() // the N is decided dynamically
let r: Box<Matrix<u8, {n}>> = todo!();
r
}
but:
- Rust will complain that
n
is not a constant - I cannot write an appropriate return type :
fn read_matrix<const N: usize>() -> Matrix<u8, N>
is not adequate, as it lets the caller choose the N, where I want N to be determined in runtime.
I can work around the second limitation by defining a trait:
trait DynamiMatrix {
fn size(&self) -> usize;
fn some_method(&self);
...
}
impl<T, const N: usize> DynamicMatrix for Matrix<T,N> {
fn size(&self) -> usize { N };
fn some_method(&self){ ... }
...
}
But, for construction, the best I can try is:
fn read_array_pair() -> Box<dyn DynamicMatrix> {
let n: usize = todo!();
let m = Box::new(Matrix { inner: [[0; n]; n] });
todo!(); // fill up m
m
}
and Rust will still complain that n is not constant.
Is there any way to achieve this? If possible without falling back to nested Vec
s, because i'd like my square invariant to be enforced?
Const parameters were deliberately designed so that they are always known at compile time. Just like most information about types in a program, the compiler will erase them without keeping this information at run-time. So the short answer is no, and it is unlikely that a direct means of specifying this kind of const parameter at run-time will ever be featured.
However, there are known workarounds to creating generic structures that may either contain compile-time or run-time information, and they even predate const parameters.
Consider this simplified definition of
ndarray::ArrayBase
:This definition is parameterized over its source of elements
S
as well as its dimensionalityD
.D
, often implemented through the primitiveDim
, will then be generic over both situations:Array2
,D
=Ix2
, enabling the user to pass a[usize; 2]
to index an element in the array.ArrayD
, in whichD
=IxDyn
and users can pass anything which Deref's to a[usize]
for indexing.The conclusion is that you may be interested in changing the design of your structs and traits so that these details (whether inferred at compile-time or at run-time) are encoded in a type parameter instead of a const parameter.