RBF*_*F06 1 arrays generics rust const-generics
我想要一个表示值数组的数据结构,但它仅支持一组特定的大小并在编译时强制执行。就像是:
struct MyArray<const N: usize>([u8; N]);
Run Code Online (Sandbox Code Playgroud)
但这样的N只能是一组特定的值,而不仅仅是 可以表示的任何数字usize。例如,我希望一个结构体可以包装 a [u8; 3]、 a[u8; 6]或 a [u8; 9],但不能包装除3、6 和 9 之外的[u8; N]任何其他结构体。我需要在编译时强制执行此约束,并且最好是N类型系统。这在 Rust 中可能吗?是否有执行此操作的标准模式或板条箱?
您可以通过仅提供所需长度的构造函数来做到这一点。
impl MyArray<3> {
pub fn new(arr: [u8; 3]) -> Self {
Self(arr)
}
}
impl MyArray<6> {
pub fn new(arr: [u8; 6]) -> Self {
Self(arr)
}
}
impl MyArray<9> {
pub fn new(arr: [u8; 9]) -> Self {
Self(arr)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在包含 的模块之外MyArray,您只能创建MyArray长度为 3、6 或 9 的值。
如果您有更多数字,宏会有所帮助。
macro_rules! impl_my_array {
($($n:expr),* $(,)?) => {$(
impl MyArray<$n> {
pub fn new(arr: [u8; $n]) -> Self {
Self(arr)
}
}
)*}
}
impl_my_array! {
3, 6, 9
}
Run Code Online (Sandbox Code Playgroud)
这些的缺点是类型推断无法确定new要调用哪个,因此每当构造值时都需要指定 const 泛型。
// V
let ma = MyArray::<3>::new([1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)
您可能想给它们不同的名称,或者提供一个更高级别的构造函数来选择特定的名称new或返回错误。
如果您需要大量数字,例如跨越整个usize范围,则需要使用该const技巧。
这个允许每一个都usize被 3 整除。
impl<const N: usize> MyArray<N> {
const LEN_IS_DIVISIBLE_BY_3: () = if N % 3 != 0 {
panic!("MyArray values must have length divisible by 3");
};
pub fn new(arr: [u8; N]) -> Self {
let _ = Self::LEN_IS_DIVISIBLE_BY_3;
Self(arr)
}
}
Run Code Online (Sandbox Code Playgroud)