const 泛型数组大小的算术推断 conditions/constraints
Arithmetic inferral conditions/constraints for const generic arraysize
我有这个函数将一个向量分成两个奇数元素和偶数元素的向量:
pub fn odd_even<T>(x: Vec<T>, upto: usize) -> (Vec<T>, Vec<T>)
where T: Copy
{
let mut odd = Vec::new();
let mut even = Vec::new();
let oddeven: [&mut Vec<T>; 2] = [&mut odd, &mut even];
for n in 0..upto
{
oddeven[1 - n%2].push(x[n]);
}
return (odd, even);
}
这工作正常并且适用于动态大小的向量。
但是,我正在考虑为此使用 const 通用长度数组。下面的代码为 LEN_ODD
和 LEN_EVEN
的约束(或者你怎么称呼它?)生成编译器错误,因为 LEN
是一个常量,但它应该传达这个想法。我什至不确定这种语言是否允许我做这种事情,但我想知道这是否可能。
有没有办法说 LEN_ODD
和 LEN_EVEN
必须对应于 LEN
的某个值,以便可以自动推断出这两个常数的值由编译器?也许这是一个愚蠢的想法,但我想尝试一下。该代码将用于实现快速傅里叶变换,其中性能至关重要。或许宏会是更好的实现方式?
fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy,
LEN_ODD == LEN << 1, // this line is invalid
LEN_EVEN == (LEN + 1) << 1 // this line is also invalid
{
let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN
{
oddeven[1 - n%2][n << 1] = x[n];
}
return (odd, even);
}
我是 Rust 的新手,对显式使用指针的语言没有太多经验。那里可能有一个解决方案,我完全错过了引用数组的第一个元素,但是数组的长度不会受到编译器的限制,这很容易让人困惑。到时候你还不如用向量对吧?
使用断言,编译器仍然不会推断 LEN_ODD
和 LEN_EVEN
:
fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy
{
assert_eq!(LEN_ODD, LEN << 1);
assert_eq!(LEN_EVEN, (LEN + 1) << 1);
let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN
{
oddeven[1 - n%2][n << 1] = x[n];
}
return (odd, even);
}
上面的最终函数可以这样成功调用:
odd_even::<usize, 4, 2, 2>([0, 2, 3, 5]); // -> [2, 5], [0, 3]
但是长度必须指定,不会被推断。我正在寻找的是一种告诉编译器如何推断它们的方法。
对 const 泛型进行算术运算需要 generic_const_exprs 特性。这是启用了该功能的代码的有效实现:
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn main() {
let _: ([u32; 2], [u32; 2]) = dbg!(odd_even([0, 2, 3, 5]));
let _: ([u32; 2], [u32; 3]) = dbg!(odd_even([0, 2, 3, 5, 6]));
}
fn odd_even<T, const LEN: usize>(x: [T; LEN]) -> ([T; LEN / 2], [T; (LEN + 1) / 2])
where
T: Default,
T: Copy,
{
let mut odd = [Default::default(); LEN / 2];
let mut even = [Default::default(); (LEN + 1) / 2];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN {
oddeven[1 - n % 2][n / 2] = x[n];
}
return (odd, even);
}
输出:
[src/main.rs:5] odd_even([0, 2, 3, 5]) = (
[
2,
5,
],
[
0,
3,
],
)
[src/main.rs:6] odd_even([0, 2, 3, 5, 6]) = (
[
2,
5,
],
[
0,
3,
6,
],
)
我有这个函数将一个向量分成两个奇数元素和偶数元素的向量:
pub fn odd_even<T>(x: Vec<T>, upto: usize) -> (Vec<T>, Vec<T>)
where T: Copy
{
let mut odd = Vec::new();
let mut even = Vec::new();
let oddeven: [&mut Vec<T>; 2] = [&mut odd, &mut even];
for n in 0..upto
{
oddeven[1 - n%2].push(x[n]);
}
return (odd, even);
}
这工作正常并且适用于动态大小的向量。
但是,我正在考虑为此使用 const 通用长度数组。下面的代码为 LEN_ODD
和 LEN_EVEN
的约束(或者你怎么称呼它?)生成编译器错误,因为 LEN
是一个常量,但它应该传达这个想法。我什至不确定这种语言是否允许我做这种事情,但我想知道这是否可能。
有没有办法说 LEN_ODD
和 LEN_EVEN
必须对应于 LEN
的某个值,以便可以自动推断出这两个常数的值由编译器?也许这是一个愚蠢的想法,但我想尝试一下。该代码将用于实现快速傅里叶变换,其中性能至关重要。或许宏会是更好的实现方式?
fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy,
LEN_ODD == LEN << 1, // this line is invalid
LEN_EVEN == (LEN + 1) << 1 // this line is also invalid
{
let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN
{
oddeven[1 - n%2][n << 1] = x[n];
}
return (odd, even);
}
我是 Rust 的新手,对显式使用指针的语言没有太多经验。那里可能有一个解决方案,我完全错过了引用数组的第一个元素,但是数组的长度不会受到编译器的限制,这很容易让人困惑。到时候你还不如用向量对吧?
使用断言,编译器仍然不会推断 LEN_ODD
和 LEN_EVEN
:
fn odd_even<T, const LEN: usize, const LEN_ODD: usize, const LEN_EVEN: usize>
(x: [T; LEN]) -> ([T; LEN_ODD], [T; LEN_EVEN])
where
T: Default, T: Copy
{
assert_eq!(LEN_ODD, LEN << 1);
assert_eq!(LEN_EVEN, (LEN + 1) << 1);
let mut odd: [T; LEN_ODD] = [Default::default(); LEN_ODD];
let mut even: [T; LEN_EVEN] = [Default::default(); LEN_EVEN];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN
{
oddeven[1 - n%2][n << 1] = x[n];
}
return (odd, even);
}
上面的最终函数可以这样成功调用:
odd_even::<usize, 4, 2, 2>([0, 2, 3, 5]); // -> [2, 5], [0, 3]
但是长度必须指定,不会被推断。我正在寻找的是一种告诉编译器如何推断它们的方法。
对 const 泛型进行算术运算需要 generic_const_exprs 特性。这是启用了该功能的代码的有效实现:
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
fn main() {
let _: ([u32; 2], [u32; 2]) = dbg!(odd_even([0, 2, 3, 5]));
let _: ([u32; 2], [u32; 3]) = dbg!(odd_even([0, 2, 3, 5, 6]));
}
fn odd_even<T, const LEN: usize>(x: [T; LEN]) -> ([T; LEN / 2], [T; (LEN + 1) / 2])
where
T: Default,
T: Copy,
{
let mut odd = [Default::default(); LEN / 2];
let mut even = [Default::default(); (LEN + 1) / 2];
let oddeven: [&mut [T]; 2] = [&mut odd, &mut even];
for n in 0..LEN {
oddeven[1 - n % 2][n / 2] = x[n];
}
return (odd, even);
}
输出:
[src/main.rs:5] odd_even([0, 2, 3, 5]) = (
[
2,
5,
],
[
0,
3,
],
)
[src/main.rs:6] odd_even([0, 2, 3, 5, 6]) = (
[
2,
5,
],
[
0,
3,
6,
],
)