rust - 传递给函数的引用仍然是借用的
问题描述
考虑以下 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 行,甚至不需要内部范围。
解决方案
让我们考虑这个例子:
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
。但是你不能打电话g
,x
因为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
但是调用foo
asfoo(&mut x, |a| a, |a| a);
变得合法。
推荐阅读
- python - 使用 python selenium 在 p 标签中查找表数据
- python - 向 tk.Button 子类添加 kwarg 时出现问题
- python - 在布尔索引中对变量进行分组
- regex - Telegram Bot API 4.5 MarkdownV2 上的转义字符给超链接带来麻烦
- java - 无法将消息从 Json 字符串转换为对象。ClassCastException
- python - 如果每个单元格包含具有这些值的列表,如何计算矩阵中每个单元格的值的平均值
- go - 利用 goroutine 和通道实现自上而下的树构建功能
- php - 一次使用多个 PDO 准备好的语句
- typescript - Typescript中函数的内部是在外部之后处理的,虽然外部的代码写在内部下面
- mysql - SQL 查询如何替换所有缩略图大小并将其设置为全尺寸(WordPress)