为什么这不能通过借用检查器?

问题描述

我试图通过一一拆分顶行和底行来解决 leetcode 上的螺旋顺序问题,但我遇到了一个我无法理解的借用检查器问题。这是产生编译错误的最小示例:

pub fn f(mut matrix: &mut [Vec<i32>]) {
    while let Some((_,remainder)) = matrix.split_first_mut() {
        matrix = remainder;
        if let Some((_,remainder)) = matrix.split_first_mut() {
            matrix = remainder;
        }
    }
}

这是我的完整代码,用于说明我要完成的内容

impl Solution {
    pub fn spiral_order(mut matrix: Vec<Vec<i32>>) -> Vec<i32> {
        let mut matrix = &mut matrix[..];
        if matrix.is_empty() {
            return Vec::new();
        }
        let mut ans = Vec::with_capacity(matrix.len() * matrix[0].len());
        while let Some((head,tail)) = matrix.split_first_mut() {
            ans.append(head);
            matrix = tail;
            for row in matrix.iter_mut() {
                ans.push(row.pop().unwrap());
            }
            if let Some((head,tail)) = matrix.split_last_mut() {
                matrix = tail;
                ans.extend(head.into_iter().rev().map(|&mut x| x));
            }
        }
        ans
    }
}

似乎认为在循环的下一次迭代中内部借用与随后的外部借用冲突,但我认为应该没问题,因为我将余数移回矩阵,所以有一个有效的{{1}在迭代结束之前在那里。为什么编译失败,应该如何修复?

解决方法

我无法解释为什么您的原始版本无法编译,但我认为 split_first_mutsplit_last_mut 不是这项工作的工具。我想通过切换到 removepop 来简化实现并使其编译:

fn spiral_order(mut matrix: Vec<Vec<i32>>) -> Vec<i32> {
    if matrix.is_empty() {
        return Vec::new();
    }
    let mut ans = Vec::with_capacity(matrix.len() * matrix[0].len());
    while !matrix.is_empty() {
        let mut head = matrix.remove(0);
        ans.append(&mut head);
        for row in matrix.iter_mut() {
            ans.push(row.pop().unwrap());
        }
        if let Some(head) = matrix.pop() {
            ans.extend(head.into_iter().rev());
        }
    }
    ans
}

playground


更优的解决方案,没有任何 matrix 突变或副本:

fn spiral_order(matrix: Vec<Vec<i32>>) -> Vec<i32> {
    if matrix.len() == 0 || matrix[0].len() == 0 {
        return Vec::new();
    }

    let mut row = 0;
    let mut col = 0;
    let mut up = 0;
    let mut down = matrix.len() as i32 - 1;
    let mut left = 0;
    let mut right = matrix[0].len() as i32 - 1;
    let mut dir = (0,1);
    let mut ans = Vec::with_capacity(matrix.len() * matrix[0].len());

    for _ in 0..(matrix.len() * matrix[0].len()) {
        ans.push(matrix[row as usize][col as usize]);

        match dir {
            (0,1) if col == right => {
                dir = (1,0);
                up += 1;
            }
            (1,0) if row == down => {
                dir = (0,-1);
                right -= 1;
            }
            (0,-1) if col == left => {
                dir = (-1,0);
                down -= 1;
            }
            (-1,0) if row == up => {
                dir = (0,1);
                left += 1;
            }
            _ => (),}

        row += dir.0;
        col += dir.1;
    }

    ans
}

playground