Vec<Vec的可变和不可变借用问题<i32>>



我正在解决一个来自Leetcode的问题,并遇到Rust不允许我有效执行它的事实。我做错了什么?我知道关于参考文献和借阅的书的文章,我想知道如何解决这个问题,尽管语言的特殊性。

我试图为一个应该改变的vec和另一个不会改变的vec创建一个引用。拉斯特不会让我这么做的。该程序可以工作,但只有在使用.clone()时才能工作,这将非常缓慢且没有必要(last_row不会在任何地方更改,只是从那里派生值)。

下面是工作代码:
use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let last_row = & triangle[i+1].clone();
let current_row = &mut triangle[i];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}

如您所见,我使用.clone()来修复在尝试使用引用编写程序时出现的借用检查器错误:

use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let current_row = &mut triangle[i];
let last_row = &triangle[i+1];
for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}

终端:

error[E0502]: cannot borrow `triangle` as immutable because it is also borrowed as mutable
--> srcmain.rs:6:25
|
5 |         let current_row = &mut triangle[i];
|                                -------- mutable borrow occurs here
6 |         let last_row = &triangle[i+1];
|                         ^^^^^^^^ immutable borrow occurs here
7 |         for j in 0..current_row.len() {
|                     ----------------- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.

然而,当试图写一个糟糕的程序时,一切都正常工作,没有任何问题:

use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
for j in 0..triangle[i].len() {
triangle[i][j] = cmp::min(triangle[i+1][j], triangle[i+1][j+1]) + triangle[i][j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}

您可以通过split_at_mut()方法完成此操作,该方法来自原始片类型(Vec自动转换为原始片类型)。此方法允许您安全地获取可变片并在给定索引处将其拆分为两个可变片,因为可以保证这两个片不会重叠。(注意,这是零复制,因为切片只是借用现有连续序列的胖指针。)

为了进行借用检查,这两个片是独立的,因此您可以同时从两个片中可变地借用(或者,在您的情况下,从一个片中可变地借用,从另一个片中不可变地借用)。

use std::cmp;
fn minimum_total(mut triangle: Vec<Vec<i32>>) -> i32 {
for i in (0..triangle.len()-1).rev() { // from penultimate (last - 1) to first
let (left, right) = triangle.split_at_mut(i + 1);

let current_row = left.last_mut().unwrap();
let last_row = right.first().unwrap();

for j in 0..current_row.len() {
current_row[j] = cmp::min(last_row[j], last_row[j+1]) + current_row[j];
}
}
triangle[0][0]
}
fn main() {
println!("{}", minimum_total(vec![vec![2],vec![3,4],vec![6,5,7],vec![4,1,8,3]]));
}

是的,这就是Rust——你必须以一种编译器可以判断它是安全的方式编写代码。有时这需要一点思考,但通常最终你的代码会比你原本编写的代码更干净。

想象一下,有一个函数可以一次遍历两个项,调用你在它们上面指定的函数,第一个是不可变的,第二个是可变的。将其命名为pairs_mut,并在a,b,c,d上用函数f调用它,将导致调用f(&a, &mut b),f(&b, &mut c)f(&c, &mut d)。非泛型版本并不难编写。我不太愿意把代码放在这里,因为你想从练习中学习。

注意:我怀疑Rust生态系统中存在这样的工具(或者更通用的东西),但是我在Iterator和itertools crate中找过了,没有找到任何东西。如果你知道有这样的设施,请在评论中分享链接。否则,也许我应该试着在itertools中添加一些东西。

现在给定pairs_mut,我希望您可以看到minimum_total可以在triangle.rev()上运行它,并进行一些动态规划以得出最小和。如果你想让我在这里放一些实际的代码,请告诉我,但我鼓励你先自己尝试一下。

最新更新