可变借用以用于结构保持参考问题

Dal*_*ale 3 rust

我遇到一个结构问题,我作为一个可变参考传递.只有在定义结构以保存引用时才会出现此问题.

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);
}
Run Code Online (Sandbox Code Playgroud)

借款检查员抱怨如下:

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() {
...
}
^
Run Code Online (Sandbox Code Playgroud)

但是,如果我更改代码以使该字段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);
}
Run Code Online (Sandbox Code Playgroud)

我尝试do_task用另一个范围包围函数调用,但它没有任何效果.

为什么有引用将可变借位扩展到main的末尾,并且有什么方法可以解决这个问题吗?

我在用 rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)

Chr*_*gan 6

问题是你不小心将Global通用生命周期参数与可变借用的生命周期联系在一起.

当你需要时&'a mut Global<'a>,这意味着可变借用的持续时间Global必须与参考数一样长,即存在的two全长Global.因此,global当你写作时,你已经推断出永久借用&mut 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

每个&mut global都是借用global直到'a块结束,所以第二个与第一个冲突.

你希望分别对待这两个生命周期.该函数应该,而不是使用具体的生命周期,绑定一个生命周期参数:这是这样F: for<'b> Fn(&'b mut Global) -> &'b R读:" F应该,给定一个任意的生命周期'b,实现Fn(&'b mut Global) -> &'b R".然后使用lifetime参数写入实际函数以Global将其删除,以便将其推断为另一个任意生命周期,如下所示:

fn one<'a>(global: &'a mut Global) -> &'a i32 {
    &global.one
}
Run Code Online (Sandbox Code Playgroud)

这是最终结果:

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);
}
Run Code Online (Sandbox Code Playgroud)