Rust编写Python扩展:二维bool数组行XOR编译错误解决
问题:Rust编写Python扩展时数组异或操作报错
我要写一个能被Python调用的Rust函数,需求很简单:接收二维布尔数组,把第二行和第一行做XOR操作后赋值给第一行。代码如下:
use numpy::PyArray2; use pyo3::prelude::{pymodule, PyModule, PyResult, Python}; #[pymodule] fn state_generator(_py: Python<'_>, m: &PyModule) -> PyResult<()> { #[pyfn(m)] fn random_cnots_transformation(_py: Python<'_>, x: &PyArray2<bool>) { let mut array = unsafe { x.as_array_mut() }; let source = array.row(1); let mut target = array.row_mut(0); target ^= source; } Ok(()) }
用maturin编译时出现以下错误:
error[E0271]: type mismatch resolving `<ViewRepr<&mut bool> as RawData>::Elem == ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` --> src/lib.rs:35:16 | 35 | target ^= source; | ^^ expected `bool`, found `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` | = note: expected type `bool` found struct `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` = note: required for `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>` to implement `BitXorAssign<ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>>` error[E0277]: the trait bound `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>: ScalarOperand` is not satisfied --> src/lib.rs:35:16 | 35 | target ^= source; | ^^ the trait `ScalarOperand` is not implemented for `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` | = help: the following other types implement trait `ScalarOperand`: bool isize i8 i16 i32 i64 i128 usize and 9 others = note: required for `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>` to implement `BitXorAssign<ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>>` error[E0271]: type mismatch resolving `<ViewRepr<&bool> as RawData>::Elem == ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` --> src/lib.rs:35:16 | 35 | target ^= source; | ^^ expected `bool`, found `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` | = note: expected type `bool` found struct `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` = note: required for `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` to implement `BitXorAssign` = note: 1 redundant requirement hidden = note: required for `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>` to implement `BitXorAssign<ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>>` error[E0277]: the trait bound `ViewRepr<&bool>: DataMut` is not satisfied --> src/lib.rs:35:16 | 35 | target ^= source; | ^^ the trait `DataMut` is not implemented for `ViewRepr<&bool>` | = help: the trait `DataMut` is implemented for `ViewRepr<&'a mut A>` = note: required for `ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>` to implement `BitXorAssign` = note: 1 redundant requirement hidden = note: required for `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>` to implement `BitXorAssign<ArrayBase<ViewRepr<&bool>, Dim<[usize; 1]>>>`
我以为是^=操作符的问题,换成+=还是报错:
error[E0368]: binary assignment operation `+=` cannot be applied to type `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>` --> src/lib.rs:35:9 | 35 | target += source; | ------^^^^^^^^^^ | | | cannot use `+=` on type `ArrayBase<ViewRepr<&mut bool>, Dim<[usize; 1]>>`
我看过相关的技术回答,但不确定差异在哪里。我猜问题出在我的array是ArrayViewMut<bool, Ix2>,而示例里是Array2。请问要修改哪些部分才能实现这个操作?
我的Cargo版本是1.72.0,Cargo.toml配置如下:
[package] name = "state_generator" version = "0.1.0" authors = ["Tristan NEMOZ"] edition = "2021" [lib] crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ndarray = "0.15.6" numpy = "0.19.0" rand = "0.8.5" [dependencies.pyo3] version = "0.19.2" features = ["extension-module"]
解决方案
问题核心是:ndarray的视图(ArrayView/ArrayViewMut)没有直接实现数组间的BitXorAssign批量操作,需要改用元素级遍历的方式完成异或。
修改后的代码如下:
use numpy::PyArray2; use ndarray::Zip; use pyo3::prelude::{pymodule, PyModule, PyResult, Python}; #[pymodule] fn state_generator(_py: Python<'_>, m: &PyModule) -> PyResult<()> { #[pyfn(m)] fn random_cnots_transformation(_py: Python<'_>, x: &PyArray2<bool>) { let mut array = unsafe { x.as_array_mut() }; let source = array.row(1); let mut target = array.row_mut(0); // 使用Zip工具逐元素执行异或 Zip::from(&mut target) .and(&source) .for_each(|t, s| *t ^= *s); } Ok(()) }
说明
Zip是ndarray提供的高效元素遍历工具,能安全同步遍历多个数组/视图的对应元素- 直接操作每个元素的引用,避开了视图间批量操作符未实现的问题
- 保持原逻辑,直接修改输入数组,无需额外内存分配
也可以用基础的迭代器组合实现,效果一致:
for (t, s) in target.iter_mut().zip(source.iter()) { *t ^= *s; }
这两种方式都能解决类型不匹配问题,同时保证执行效率。
内容的提问来源于stack exchange,提问作者Tristan Nemoz
相关产品推荐
相关产品推荐

