Rust中如何将一维迭代器结果构造为二维数组实现逐元素相加
Rust 固定大小二维数组逐元素加法实现
你不需要把数组扁平化再重组,Rust 标准库提供了更适配固定长度数组的初始化方式,完全可以避免默认值填充的额外开销。
最优实现(无依赖、零额外开销)
直接用std::array::from_fn,它会按索引位置直接计算每个元素的值,不会先填充默认值再覆盖,编译后的代码和手写最优循环性能完全一致,不需要T实现Default trait:
const ROW: usize = 3; const COL: usize = 3; // 假设T支持加法,Add输出类型为T本身 let result: [[T; COL]; ROW] = std::array::from_fn(|i| { std::array::from_fn(|j| d1[i][j] + d2[i][j]) });
扁平化迭代器思路的补全方法
标准库的collect()默认不能直接收集为固定大小数组,因为固定大小数组的长度在编译期确定,收集时无法在编译期验证迭代器长度和数组长度匹配。如果一定要走扁平化迭代器的逻辑,需要先收集到Vec再转固定长度数组,不过这个写法会产生堆分配开销,性能比上面的from_fn差:
let result: [[T; 3]; 3] = d1.iter() .zip(d2.iter()) .map(|(row1, row2)| { row1.iter() .zip(row2.iter()) .map(|(a, b)| a + b) .collect::<Vec<_>>() .try_into() .unwrap() }) .collect::<Vec<_>>() .try_into() .unwrap();
不推荐实际项目中用这个写法,堆分配带来的开销比你一开始想避免的默认值初始化开销还大。
低版本Rust兼容写法(无std依赖场景可用)
如果你的Rust版本低于1.63(array::from_fn是1.63版本稳定的),可以用MaybeUninit手动实现无开销初始化,跳过默认值填充步骤:
use std::mem::MaybeUninit; let mut result: [[MaybeUninit<T>; 3]; 3] = unsafe { MaybeUninit::uninit().assume_init() }; for i in 0..3 { for j in 0..3 { result[i][j].write(d1[i][j] + d2[i][j]); } } // 所有元素都已完成初始化,直接转成目标类型即可 let result: [[T; 3]; 3] = unsafe { std::mem::transmute(result) };
这段是unsafe代码,只要保证循环覆盖了所有数组位置,就不会产生未定义行为。
内容的提问来源于stack exchange,提问作者Julian Aßmann
相关产品推荐
相关产品推荐

