我刚刚编写了一个小的 Rust 程序,它计算斐波那契数并记住计算结果。它有效,但我对为什么有点困惑,尤其是递归调用。 (这也可能不是惯用语。)
这是程序:
use std::collections::HashMap;
fn main() {
let n = 42; // hardcoded for simplicity
let mut cache = HashMap::new();
let answer = fib(n, &mut cache);
println!("fib of {} is {}", n, answer);
}
fn fib(n: i32, cache: &mut HashMap<i32,i32>) -> i32 {
if cache.contains_key(&n) {
return cache[&n];
} else {
if n < 1 { panic!("must be >= 1") }
let answer = if n == 1 {
0
} else if n == 2 {
1
} else {
fib(n - 1, cache) + fib(n - 2, cache)
};
cache.insert(n, answer);
answer
}
}
以下是我对发生的事情的理解:
- In
main
, let mut cache
意思是“我希望能够改变这个哈希图(或重新分配变量)”。
- When
main
calls fib
,它通过了&mut cache
说“我借给你这个,你可以改变它。”
- 在签名中
fib
, cache: &mut Hashmap
意思是“我希望借用一个可变的 HashMap - 在允许变异的情况下借用它”
(如果我错了,请纠正我。)
但当fib
递归,调用fib(n -1, cache)
,我不需要使用fib(n -1, &mut cache)
,如果我这样做,我会得到一个错误:“无法借用不可变的局部变量cache
as mutable”。嗯?这不是一个不可变的局部变量,它是一个可变的借用 - 对吧?
如果我尝试fib(n - 1, &cache)
,我得到一个略有不同的错误:
error: mismatched types:
expected `&mut std::collections::hash::map::HashMap<i32, i32>`,
found `&&mut std::collections::hash::map::HashMap<i32, i32>`
这看起来像是在说“我期望一个可变引用并获得了对可变引用的引用”。
我知道fib
正在递归调用中借出,因为如果它放弃所有权,它就无法调用cache.insert
然后。我知道这不是递归的特殊情况,因为如果我定义fib2
几乎相同于fib
,我可以让它们相互递归,并且效果很好。
为什么我不需要显式借出借用的可变变量?