Reputation: 1735
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?
Upvotes: 4
Views: 2687
Reputation: 29983
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.
Upvotes: 5