【发布时间】:2015-08-05 18:58:54
【问题描述】:
我刚刚编写了一个小的 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
}
}
我是这样理解发生了什么的:
- 在
main中,let mut cache的意思是“我希望能够改变这个哈希图(或重新分配变量)”。 - 当
main调用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 几乎相同,我可以让它们相互递归并且效果很好。
为什么我不需要显式借出一个借来的可变变量?
【问题讨论】:
-
你可以传递所有权,并让函数返回一个带有答案和缓存的元组:PlayPen