我正在Rust中实现矩阵。该代码适用于该示例,但可能存在轻微错误:
#[derive(Debug, PartialEq)]
pub struct Matrix<T> {
inner: Vec<Vec<T>>,
}
impl<T> Matrix<T> {
pub fn dim(&self) -> (usize, usize) {
if self.inner.len() == 0 {
(0, 0)
} else {
(self.inner.len(), self.inner[0].len())
}
}
}
我希望能够获得矩阵的象限:
+----+----+
| Q1 | Q2 |
+----+----+
| Q3 | Q4 |
+----+----+
我介绍了Slice
和SliceMut
结构来借用矩阵的一部分:
pub struct Slice<'a, T: 'a> {
matrix: &'a Matrix<T>,
start: (usize, usize),
end: (usize, usize),
}
pub struct SliceMut<'a, T: 'a> {
matrix: &'a mut Matrix<T>,
start: (usize, usize),
end: (usize, usize),
}
现在我想实现两个功能:
quadrants
- 获得四个元组的元组quadrants_mut
- 获取四个可变片的元组我不能在quadrants_mut
中多次借用一个矩阵:
fn quadrants_mut<'a, T>(matrix: &'a mut Matrix<T>) -> (SliceMut<'a, T>, SliceMut<'a, T>, SliceMut<'a, T>, SliceMut<'a, T>) {
let (rows, cols) = matrix.dim();
let mid_rows = rows / 2;
let mid_cols = cols / 2;
let a = SliceMut { matrix: matrix, start: (0, 0), end: (mid_rows, mid_cols) };
let b = SliceMut { matrix: matrix, start: (0, mid_rows), end: (mid_cols, cols) };
let c = SliceMut { matrix: matrix, start: (mid_rows, rows), end: (0, mid_cols) };
let d = SliceMut { matrix: matrix, start: (mid_rows, rows), end: (mid_cols, cols) };
(a, b, c, d)
}
当我尝试编译时,我有一个错误:
error[E0499]: cannot borrow `*matrix` as mutable more than once at a time
--> src/matrix/slice.rs:62:13
|
59 | let a = SliceMut { matrix: matrix, start: (0, 0), end: (mid_rows, mid_cols) };
| ------ first mutable borrow occurs here
...
60 | let b = SliceMut { matrix: matrix, start: (0, mid_rows), end: (mid_cols, cols) };
| ^^^^^^ second mutable borrow occurs here
...
66 | }
我试图可变地借用矩阵四次。我应该如何更改代码以使其编译?
答案 0 :(得分:0)
Safe Rust不允许同时拥有多个可变绑定。这是通过检查绑定类型(是否可变)和计数来实现的。编译器不是那么聪明,无法完全理解你的意图,因此可以告诉你,你使用的切片永远不会相交。通过在代码中包含多个可变引用,甚至是数据的不同部分,您仍然违反了规则。
作为一种解决方案,可以使用一个引用和索引来为您提供象限数据:begin
和end
索引,或仅begin
和count
:
pub struct SliceMut<'a, T: 'a> {
matrix: &'a mut Matrix<T>,
quadrants: Vec<(Range<usize>, Range<usize>)>,
}
fn quadrants_mut<'a, T>(matrix: &'a mut Matrix<T>) -> SliceMut<'a, T> {
let (rows, cols) = matrix.dim();
let mid_rows = rows / 2;
let mid_cols = cols / 2;
SliceMut {
matrix: matrix,
quadrants: vec![
(0..0, mid_rows..mid_cols),
(0..mid_rows, mid_cols..cols),
(mid_rows..rows, 0..mid_cols),
(mid_rows..rows, mid_cols..cols),
],
}
}
对于split_at_mut
,它使用不安全的Rust并实现了as the following:
#[inline]
fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
let len = self.len();
let ptr = self.as_mut_ptr();
unsafe {
assert!(mid <= len);
(from_raw_parts_mut(ptr, mid),
from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
}
}
答案 1 :(得分:0)
你想做什么,绝对是可能的。但是很难。 真的 很难。
幸运的是,我只会展示如何做好事。
如果您查看split_at_mut
的实施方式,您可以注意到它需要您创建一个模仿quadrants_mut
的返回值的并行结构(即SliceMut
):
pub struct SliceMut<'a, T: 'a> {
matrix: &'a mut Matrix<T>,
start: (usize, usize),
end: (usize, usize),
}
#[repr(C)]
struct MatrixRaw<T> {
data: *const Matrix<T>,
start: (usize, usize),
end: (usize, usize),
}
注意这两种结构之间的相似性。如果他们在任何时候出现分歧,您的mem::transmute
将停止工作,或者您的安全代码会遇到段错误。
然后我们创建一个方法,将MatrixRaw
转换为SliceMut
。
#[inline]
pub unsafe fn from_raw_mat_mut<'a, T>(
p: *mut Matrix<T>,
start: (usize, usize),
end: (usize, usize),
) -> SliceMut<'a, T> {
mem::transmute(MatrixRaw {
data: p,
start: start,
end: end,
})
}
最后一步,我们向unsafe
添加quadrant_mut
块:
unsafe {
let a = from_raw_mat_mut(matrix, (0, 0), (mid_rows, mid_cols));
let b = from_raw_mat_mut(matrix, (0, mid_rows), (mid_cols, cols));
let c = from_raw_mat_mut(matrix, (mid_rows, rows), (0, mid_cols));
let d = from_raw_mat_mut(matrix, (mid_rows, rows), (mid_cols, cols));
(a, b, c, d)
}
HARD PART:这是困难的部分 - 确保您的方法和迭代器不会意外地使您的数据和不变量无效。这在Matrix
案例中极难实现。
为什么呢?好吧,因为没有一种很好的方式来对你的数据说,&#34;不要触摸这些部分&#34;就像你可以使用数组。使用数组,您只需抵消数据,就可以了。但是Matrix
?这并非不可能,但我怀疑我不知道一种不会引入性能损失的方式。