Rust 是否支持具有运行时确定值的常量泛型类型?
Does rust support const-generic types with a runtime-determined value?
考虑 const-generic 数据结构的经典示例:方矩阵。
struct Matrix<T, const N: usize> {
inner: [[T; N]; N]
}
我想要return一个结构体,其常量参数是动态定义的:
fn read_matrix() -> ??? {
let n: usize = todo!() // the N is decided dynamically
let r: Box<Matrix<u8, {n}>> = todo!();
r
}
但是:
- Rust 会抱怨
n
不是常量
- 我写不出合适的 return 类型:
fn read_matrix<const N: usize>() -> Matrix<u8, N>
是不够的,因为它让调用者选择 N,而我希望 N 在运行时确定。
我可以通过定义特征来解决第二个限制:
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){ ... }
...
}
但是,对于构造,我能尝试的最好的是:
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
}
Rust 仍然会抱怨 n 不是常量。
有什么办法可以实现吗?如果可能而不回退到嵌套 Vec
s,因为我希望我的平方不变量被强制执行?
Const 参数是有意设计的,以便它们在编译时始终是已知的。就像程序中有关类型的大多数信息一样,编译器会在 运行 时删除它们而不保留此信息。
所以简短的回答是否定的,并且不太可能在 运行 时间指定这种常量参数的直接方法将成为特色。
但是,创建可能包含编译时或 运行 时信息的通用结构有已知的解决方法,它们甚至早于 const 参数。
考虑 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,
}
此定义在其 元素来源 S
及其维度 D
上进行了参数化。 D
,通常通过原语 Dim
实现,然后将在两种情况下通用:
- 对于固定数量的维度,例如
Array2
, D
= Ix2
,使用户能够传递 [usize; 2]
来索引数组中的元素。
- 如果维数在编译时未知,则存在
ArrayD
,其中 D
= IxDyn
并且用户可以将 Deref 的任何内容传递给 [usize]
用于索引。
结论是您可能有兴趣更改结构和特征的设计,以便将这些细节(无论是在编译时还是在 运行 时推断)编码为 键入参数 而不是 const 参数。
考虑 const-generic 数据结构的经典示例:方矩阵。
struct Matrix<T, const N: usize> {
inner: [[T; N]; N]
}
我想要return一个结构体,其常量参数是动态定义的:
fn read_matrix() -> ??? {
let n: usize = todo!() // the N is decided dynamically
let r: Box<Matrix<u8, {n}>> = todo!();
r
}
但是:
- Rust 会抱怨
n
不是常量 - 我写不出合适的 return 类型:
fn read_matrix<const N: usize>() -> Matrix<u8, N>
是不够的,因为它让调用者选择 N,而我希望 N 在运行时确定。
我可以通过定义特征来解决第二个限制:
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){ ... }
...
}
但是,对于构造,我能尝试的最好的是:
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
}
Rust 仍然会抱怨 n 不是常量。
有什么办法可以实现吗?如果可能而不回退到嵌套 Vec
s,因为我希望我的平方不变量被强制执行?
Const 参数是有意设计的,以便它们在编译时始终是已知的。就像程序中有关类型的大多数信息一样,编译器会在 运行 时删除它们而不保留此信息。 所以简短的回答是否定的,并且不太可能在 运行 时间指定这种常量参数的直接方法将成为特色。
但是,创建可能包含编译时或 运行 时信息的通用结构有已知的解决方法,它们甚至早于 const 参数。
考虑 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,
}
此定义在其 元素来源 S
及其维度 D
上进行了参数化。 D
,通常通过原语 Dim
实现,然后将在两种情况下通用:
- 对于固定数量的维度,例如
Array2
,D
=Ix2
,使用户能够传递[usize; 2]
来索引数组中的元素。 - 如果维数在编译时未知,则存在
ArrayD
,其中D
=IxDyn
并且用户可以将 Deref 的任何内容传递给[usize]
用于索引。
结论是您可能有兴趣更改结构和特征的设计,以便将这些细节(无论是在编译时还是在 运行 时推断)编码为 键入参数 而不是 const 参数。