The ability to interchangeably borrow to deal with structural problems

I am having problems with a struct that I am passing as a mutable link. The problem only occurs when the structure is defined to hold the link.

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);
}

      

The borrow controller complains about the following:

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() {
...
}
^

      

But if I change the code so that the field is two

not a link like in the following example, it passes.

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);
}

      

I tried to surround the function calls with a do_task

different scope, but it had no effect.

Why does the link refer to mutable borrowing to the end of main, and is there any way to do this?

I use rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)

+3


source to share


1 answer


The problem is that you accidentally associated the shared lifetime parameter Global

s with the lifetime of the modified borrow.

If you require &'a mut Global<'a>

, this means that the length of the volatile borrowing Global

must be the same as the reference in two

-thus, the full length of existence Global

. So you've done what you think you would consider an ongoing loan Global

when you write &mut global

. I'll write it this way in syntax that is not valid, but gets a dot in:

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);
    }
}

      

Everyone &mut global

borrows Global

until the end of the block 'a

, so the second collides with the first.



You want to separate these two lifetimes. The function should, and not use a specific lifetime, bind the lifetime parameter: F: for<'b> Fn(&'b mut Global) -> &'b R

read it as follows: " F

should, given an arbitrary lifetime 'b

, implement Fn(&'b mut Global) -> &'b R

". The actual functions are then written with the lifetime until parameter Global

, so it can be outputted as another arbitrary lifetime, for example:

fn one<'a>(global: &'a mut Global) -> &'a i32 {
    &global.one
}

      

Gets the final result:

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);
}

      

+6


source







All Articles