首页 > 解决方案 > 传递给函数的引用仍然是借用的

问题描述

考虑以下 Rust 代码:

fn foo<'a, T, F, G>(x: &'a mut T, f: F, g: G)
where
    T: 'a,
    F: Fn(&'a T) -> &'a T,
    G: Fn(&'a mut T) -> &'a mut T,
{
    {
        f(x);
    }
    g(x);
}

fn main() {
    let mut x = 5;
    foo(&mut x, |a| a, |a| a);
}

这会产生编译器错误:

error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
  --> src/main.rs:10:7
   |
8  |         f(x);
   |           - immutable borrow occurs here
9  |     }
10 |     g(x);
   |       ^ mutable borrow occurs here
11 | }
   | - immutable borrow ends here

我不明白为什么x在第 11 行结束的不可变借用。一方面,f(x)在第 9 行结束的内部范围内。但是,返回值f(x)没有绑定到任何变量,所以我认为借用应该结束第 8 行,甚至不需要内部范围。

标签: rust

解决方案


让我们考虑这个例子

fn foo<'a, T, F, G>(x: &'a mut T, mut f: F, g: G)
where
    T: 'a,
    F: FnMut(&'a T) -> &'a T,
    G: Fn(&'a mut T) -> &'a mut T,
{
    {
        f(x);
    }
}

fn main() {
    let mut x = 5;
    let mut y = std::cell::RefCell::new(&0);
    foo(&mut x, |a| { y.replace(&a); a }, |a| a);
}

这是完全合法的,因为该函数f保证获取与 相同生命周期的引用x,因此它可以存储对 的引用x。但是你不能打电话gx因为f可能已经存储x了。

如果您更改foo为:

fn foo<T, F, G>(x: &mut T, mut f: F, g: G)
where
    F: FnMut(&T) -> &T,
    G: Fn(&T) -> &T,

这等效于(由于生命周期省略规则):

fn foo<'a, T, F, G>(x: &'a mut T, mut f: F, g: G)
where
    T: 'a,
    F: for<'b> FnMut(&'b T) -> &'b T,
    G: for<'c> Fn(&'c T) -> &'c T,

然后f 不允许存储参考x

error: borrowed data cannot be stored outside of its closure
  --> src/main.rs:14:33
   |
13 |     let mut y = std::cell::RefCell::new(&0);
   |         -----                           -- cannot infer an appropriate lifetime...
   |         |
   |         ...so that variable is valid at time of its declaration
14 |     foo(&mut x, |a| { y.replace(&a); a }, |a| a);
   |                 ---             ^^ cannot be stored outside of its closure
   |                 |
   |                 borrowed data cannot outlive this closure

但是调用fooasfoo(&mut x, |a| a, |a| a); 变得合法


推荐阅读