为什么我不需要显式借出借来的可变变量? [英] Why do I not need to explicitly lend a borrowed, mutable variable?
问题描述
我刚刚编写了一个小型 Rust 程序,它计算斐波那契数并记住计算结果.它有效,但我对原因有点困惑,尤其是递归调用.(这也可能不是惯用语.)
I've just written a small Rust program which calculates Fibonacci numbers and memoizes the calculation. It works, but I'm a little confused about why, especially the recursive call. (It also probably isn't idiomatic.)
程序如下:
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
}
}
以下是我对正在发生的事情的理解:
Here's how I understand what's going on:
- 在
main
中,let mut cache
的意思是我希望能够改变这个hashmap(或重新分配变量)". - 当
main
调用fib
时,它通过&mut cache
说我借给你这个,你被允许改变它." - 在
fib
的签名中,cache: &mut Hashmap
的意思是我希望借给一个可变的 HashMap - 借用它并允许变异"立>
- In
main
,let mut cache
means "I want to be able to mutate this hashmap (or re-assign the variable)". - When
main
callsfib
, it passes&mut cache
to say "I'm lending you this, and you're allowed to mutate it." - In the signature of
fib
,cache: &mut Hashmap
means "I expect to be lent a mutable HashMap - to borrow it with permission to mutate"
(如果我错了,请纠正我.)
(Please correct me if I'm wrong.)
但是当fib
递归调用fib(n -1, cache)
时,我不需要使用fib(n -1, &mut缓存)
,如果我这样做,我会得到一个错误:不能借用不可变的局部变量 cache
作为可变的".嗯?它不是一个不可变的局部变量,它是一个可变的借用 - 对吧?
But when fib
recurses, calling fib(n -1, cache)
, I do not need to use fib(n -1, &mut cache)
, and I get an error if I do: "cannot borrow immutable local variable cache
as mutable". Huh? It's not an immutable local variable, it's a mutable borrow - right?
如果我尝试 fib(n - 1, &cache)
,我会得到一个稍微不同的错误:
If I try fib(n - 1, &cache)
, I get a slightly different error:
error: mismatched types:
expected `&mut std::collections::hash::map::HashMap<i32, i32>`,
found `&&mut std::collections::hash::map::HashMap<i32, i32>`
这看起来像是在说我期待一个可变引用并得到了一个对可变引用的引用".
Which looks like it's saying "I expected a mutable reference and got a reference to a mutable reference".
我知道 fib
在递归调用中借出,因为如果它放弃所有权,它之后就不能调用 cache.insert
.而且我知道这不是递归的特例,因为如果我将 fib2
定义为与 fib
几乎相同,我可以让它们通过彼此递归工作正常.
I know that fib
is lending in the recursive call because if it gave up ownership, it couldn't call cache.insert
afterwards. And I know that this isn't a special case for recursion, because if I define fib2
to be nearly identical to fib
, I can have them recurse via each other and it works fine.
为什么我不需要明确借出借来的可变变量?
推荐答案
您的三点非常到位.当编译器不允许你通过 &mut cache
时,这是因为该值实际上已经被借用了.cache
的类型是 &mut HashMap
,所以传递 &mut cache
的结果是 类型的值>&mut &mut HashMap
.仅传递 cache
就会得到预期的类型.
Your three points are pretty much spot-on. When the compiler won't allow you to pass &mut cache
, it is because the value is actually already borrowed. The type of cache
is &mut HashMap<i32, i32>
, so passing &mut cache
results in a value of type &mut &mut HashMap<i32, i32>
. Just passing cache
results in the expected type.
特定的错误信息 cannotboring immutable local variable cache as mutable
被触发,因为变量 cache
本身不是可变的,即使它指向的内存(HashMap
) 是.这是因为参数声明 cache: &mut HashMap
没有声明 mut
变量.这类似于 let
与 let mut
在可变性方面的不同.Rust 确实支持可变参数,在这种情况下,它看起来像 mut cache: &mut HashMap<i32, i32>
.
The specific error message cannot borrow immutable local variable cache as mutable
is triggered because the variable cache
isn't itself mutable, even though the memory it points to (the HashMap
) is. This is because the argument declaration cache: &mut HashMap<i32, i32>
doesn't declare a mut
variable. This is similar to how a let
differs in mutability from a let mut
. Rust does support mutable arguments, which in this case would look like mut cache: &mut HashMap<i32, i32>
.
这篇关于为什么我不需要显式借出借来的可变变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!