rust - 如何在 Rust 中实现向量的多个可变借用?

标签 rust

<分区>

我正在用 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 |
+----+----+

我引入了SliceSliceMut结构来借用矩阵的一部分:

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 | }

我试图可变地借用一个矩阵四次。我应该如何更改代码以使其通过编译?

最佳答案

Safe Rust 不允许同时拥有多个可变绑定(bind)。这是通过检查绑定(bind)类型(是否可变)和计数来实现的。编译器不太聪明,无法完全理解您的意图,因此可以告诉您您使用的切片永远不会相交。通过在您的代码中使用多个可变引用,即使是对数据的不同部分,您仍然违反了规则。

作为一种解决方案,可以使用一个引用和索引来为您提供象限数据:它的 beginend 索引,或者只是 begincount:

playground

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))
    }
}

关于rust - 如何在 Rust 中实现向量的多个可变借用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48420218/

相关文章:

rust - 在 Rust 中将一种类型映射到另一种类型

c++ - 如何在 C++ 中启用 Rust 所有权范式

rust - Rust:如何将可变变量传递给函数

tree - 如何在 Rust 中实现可变的仙人掌堆栈?

binary - 如何将二进制值输入 Rust 中的向量?

rust - Rust 错误 : cannot call a method whose type contains a self-type through an object

rust - 如何习惯性地将Option <T>转换为Result <T,()>?

rust - 如何将 Rust 代码编译为裸机 32 位 x86 (i686) 代码?我应该使用什么编译目标?

struct - 我如何声明我想要一个包含对实现特征的东西的引用的结构?

rust - 用 cargo 安装未注册的箱子