可变借用以解决结构持有参考问题
Mutable borrow to function for struct holding reference issues
我在使用作为可变引用传递的结构时遇到问题。只有当结构被定义为保存引用时才会出现此问题。
struct Global<'a> {
one: i32,
two: &'a i32
}
fn do_task<'a, F, R: 'a>(global: &'a mut Global<'a>, task: F)
where F: Fn(&'a mut Global<'a>) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global<'a>) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global<'a>) -> &'a i32 {
global.two
}
fn main() {
let number = 2;
let mut global = Global {
one: 1,
two: &number
};
do_task(&mut global, one);
do_task(&mut global, two);
}
借用检查员抱怨如下:
error: cannot borrow `global` as mutable more than once at a time
do_task(&mut global, two);
^~~~~~
note: previous borrow of `global` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `global` until the borrow ends
do_task(&mut global, one);
^~~~~~
note: previous borrow ends here
fn main() {
...
}
^
但是,如果我更改代码以使字段 two
不是引用,如下例所示,那么它就会通过。
struct Global {
one: i32,
two: i32,
}
fn do_task<'a, F, R: 'a>(global: &'a mut Global, task: F)
where F: Fn(&'a mut Global) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global) -> &'a i32 {
&global.two
}
fn main() {
let mut global = Global {
one: 1,
two: 2
};
do_task(&mut global, one);
do_task(&mut global, two);
}
我尝试用另一个范围包围 do_task
函数调用,但没有效果。
为什么让引用将可变借用扩展到 main 的末尾,有什么办法解决这个问题吗?
我正在使用rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
问题是您不小心将 Global
的通用生命周期参数与可变借用的生命周期联系在一起。
当您需要 &'a mut Global<'a>
时,这意味着 Global
的可变借用的持续时间必须与 two
中的引用一样长——因此, Global
的存在。因此,当您编写 &mut global
时,您已经做出了被推断为永久借用 global
的内容。我会用这样的语法来写它,它的语法不太有效,但能说明问题:
fn main() {
'a: {
let number: i32 + 'a = 2;
let mut global: Global<'a> = Global {
one: 1,
two: &'a number,
};
do_task(&mut global: &'a mut Global<'a>, one);
do_task(&mut global: &'a mut Global<'a>, two);
}
}
每个 &mut global
都在借用 global
直到 'a
块结束,因此第二个与第一个冲突。
你希望分别对待这两世。该函数应该绑定一个生命周期参数,而不是使用具体的生命周期参数:这是 F: for<'b> Fn(&'b mut Global) -> &'b R
可以这样读:“F
应该,给定一个任意的生命周期 'b
,实现 Fn(&'b mut Global) -> &'b R
”。然后将实际函数写入 Global
的生命周期参数删除,因此可以将其推断为另一个任意生命周期,如下所示:
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
struct Global<'a> {
one: i32,
two: &'a i32
}
fn do_task<F, R>(global: &mut Global, task: F)
where F: for<'a> Fn(&'a mut Global) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global) -> &'a i32 {
global.two
}
fn main() {
let number = 2;
let mut global = Global {
one: 1,
two: &number
};
do_task(&mut global, one);
do_task(&mut global, two);
}
我在使用作为可变引用传递的结构时遇到问题。只有当结构被定义为保存引用时才会出现此问题。
struct Global<'a> {
one: i32,
two: &'a i32
}
fn do_task<'a, F, R: 'a>(global: &'a mut Global<'a>, task: F)
where F: Fn(&'a mut Global<'a>) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global<'a>) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global<'a>) -> &'a i32 {
global.two
}
fn main() {
let number = 2;
let mut global = Global {
one: 1,
two: &number
};
do_task(&mut global, one);
do_task(&mut global, two);
}
借用检查员抱怨如下:
error: cannot borrow `global` as mutable more than once at a time
do_task(&mut global, two);
^~~~~~
note: previous borrow of `global` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `global` until the borrow ends
do_task(&mut global, one);
^~~~~~
note: previous borrow ends here
fn main() {
...
}
^
但是,如果我更改代码以使字段 two
不是引用,如下例所示,那么它就会通过。
struct Global {
one: i32,
two: i32,
}
fn do_task<'a, F, R: 'a>(global: &'a mut Global, task: F)
where F: Fn(&'a mut Global) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global) -> &'a i32 {
&global.two
}
fn main() {
let mut global = Global {
one: 1,
two: 2
};
do_task(&mut global, one);
do_task(&mut global, two);
}
我尝试用另一个范围包围 do_task
函数调用,但没有效果。
为什么让引用将可变借用扩展到 main 的末尾,有什么办法解决这个问题吗?
我正在使用rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
问题是您不小心将 Global
的通用生命周期参数与可变借用的生命周期联系在一起。
当您需要 &'a mut Global<'a>
时,这意味着 Global
的可变借用的持续时间必须与 two
中的引用一样长——因此, Global
的存在。因此,当您编写 &mut global
时,您已经做出了被推断为永久借用 global
的内容。我会用这样的语法来写它,它的语法不太有效,但能说明问题:
fn main() {
'a: {
let number: i32 + 'a = 2;
let mut global: Global<'a> = Global {
one: 1,
two: &'a number,
};
do_task(&mut global: &'a mut Global<'a>, one);
do_task(&mut global: &'a mut Global<'a>, two);
}
}
每个 &mut global
都在借用 global
直到 'a
块结束,因此第二个与第一个冲突。
你希望分别对待这两世。该函数应该绑定一个生命周期参数,而不是使用具体的生命周期参数:这是 F: for<'b> Fn(&'b mut Global) -> &'b R
可以这样读:“F
应该,给定一个任意的生命周期 'b
,实现 Fn(&'b mut Global) -> &'b R
”。然后将实际函数写入 Global
的生命周期参数删除,因此可以将其推断为另一个任意生命周期,如下所示:
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
struct Global<'a> {
one: i32,
two: &'a i32
}
fn do_task<F, R>(global: &mut Global, task: F)
where F: for<'a> Fn(&'a mut Global) -> &'a R {
let result = task(global);
}
fn one<'a>(global: &'a mut Global) -> &'a i32 {
&global.one
}
fn two<'a>(global: &'a mut Global) -> &'a i32 {
global.two
}
fn main() {
let number = 2;
let mut global = Global {
one: 1,
two: &number
};
do_task(&mut global, one);
do_task(&mut global, two);
}