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:
n
is not a constantfn 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
:
pub struct ArrayBase<S, D> {
/// Data buffer / ownership information. (If owned, contains the data
/// buffer; if borrowed, contains the lifetime and mutability.)
data: S,
/// The lengths of the axes.
dim: D,
/// The element count stride per axis.
strides: D,
}
This definition is parameterized over its source of elements S
as well as its dimensionality D
. D
, often implemented through the primitive Dim
, 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 which D
= 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.