如何递归传递可变引用?

8
我将尝试使用 Rust 解决这个问题
以下是我无法编译的 Rust 代码:
use std::collections::HashMap;

fn main() {
    // initialize HashMap
    let mut fibs: HashMap<u32, u32> = HashMap::new();
    fibs.insert(0, 1);
    fibs.insert(1, 1);
    let mut n = 1;
    let mut sum = 0;
    while fib(n, &mut fibs) < 4000000 {
        sum += if fib(n, &mut fibs) % 2 == 0 {
            fib(n, &mut fibs)
        } else {
            0
        };
        n += 1;
    }
    println!("{}", sum);
}

fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {
    if !fibs.contains_key(&n) {
        fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
    }
    *fibs.get(&n).unwrap()
}

error[E0596]: cannot borrow `fibs` as mutable, as it is not declared as mutable
  --> src/main.rs:22:35
   |
20 | fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {
   |                ---- help: consider changing this to be mutable: `mut fibs`
21 |     if !fibs.contains_key(&n) {
22 |         fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
   |                                   ^^^^^^^^^ cannot borrow as mutable

error[E0499]: cannot borrow `fibs` as mutable more than once at a time
  --> src/main.rs:22:35
   |
22 |         fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
   |         ---- ------               ^^^^^^^^^ second mutable borrow occurs here
   |         |    |
   |         |    first borrow later used by call
   |         first mutable borrow occurs here

error[E0596]: cannot borrow `fibs` as mutable, as it is not declared as mutable
  --> src/main.rs:22:59
   |
20 | fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {
   |                ---- help: consider changing this to be mutable: `mut fibs`
21 |     if !fibs.contains_key(&n) {
22 |         fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
   |                                                           ^^^^^^^^^ cannot borrow as mutable

error[E0499]: cannot borrow `fibs` as mutable more than once at a time
  --> src/main.rs:22:59
   |
22 |         fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
   |         ---- ------ first borrow later used by call       ^^^^^^^^^ second mutable borrow occurs here
   |         |
   |         first mutable borrow occurs here

Rust 到 Python3 的翻译如下所示:
def main():
    fibs = {}
    fibs[0] = 1
    fibs[1] = 1
    n = 1
    summ = 0
    while fib(n, fibs) < 4000000:
        summ += fib(n, fibs) if fib(n, fibs) % 2 == 0 else 0
        n+=1
    print(summ)
    print(fibs)
def fib(n, fibs):
    if n not in fibs:
        fibs[n] = fib(n-1, fibs) + fib(n-2, fibs)
    return fibs[n]
main()

我知道这个具体的实现并不理想,但是我仅仅是为了学习这种语言。我试图只向函数传递一个hashmap的引用。如果不改变解决问题的方法,我怎么能使用可变的HashMap引用呢?如果可能的话。

1个回答

7
fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {

fibs已经是一个可变引用。在函数中,您说&mut fibs,这将得到一个可变引用到一个可变引用。这是没有用的,并且不匹配正确的类型。相反,请直接传递fibs

然后您必须拆分出两个子调用:

fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {
    if !fibs.contains_key(&n) {
        let a = fib(n - 1, fibs);
        let b = fib(n - 2, fibs);
        fibs.insert(n, a + b);
    }
    *fibs.get(&n).unwrap()
}

这是借用检查器的限制的一部分——使用&mut接收者的嵌套方法调用会导致借用错误,但将它们分成单独的语句可以解决这个问题。
正如delnan指出的那样:
“虽然取一个可变引用的可变引用并没有用,而且说明了一些困惑,但通常不是类型错误,因为解引用强制转换可以将`&mut &mut T`转换为`&mut T`,至少当编译器知道期望的是`&mut T`时。”
这反映在编译器错误消息中所说的内容中:
error[E0596]: cannot borrow `fibs` as mutable, as it is not declared as mutable
  --> src/main.rs:22:35
   |
20 | fn fib(n: u32, fibs: &mut HashMap<u32, u32>) -> u32 {
   |                ---- help: consider changing this to be mutable: `mut fibs`
21 |     if !fibs.contains_key(&n) {
22 |         fibs.insert(n, fib(n - 1, &mut fibs) + fib(n - 2, &mut fibs));
   |                                   ^^^^^^^^^ cannot borrow as mutable

的确,进行建议的更改可以使代码继续执行到下一个错误。然而,像这样嵌套引用会使事情变得过于复杂,因此最好保持适当数量的引用。


尽管获取可变引用的可变引用并不实用且表现出一些混淆,但通常不会导致类型错误,因为解引用强制转换可以将 &mut &mut T 转换为 &mut T,至少当编译器知道期望的是 &mut T 时。 - user395760
@ljeabmreosn 是的,那是昨晚打字打得有点困了。现在已经修复了,并更新了delnan的评论。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接