The code in the link above is not practical, it's just a abstracted version of a code which I'm writing.
If you compile the code above, it will emit an error like this:
error[E0506]: cannot assign to `*data` because it is borrowed
--> src/main.rs:15:9
|
10 | fn foo<'a, F>(data: &'a mut Data, f: F)
| -- lifetime `'a` defined here
...
15 | *data = Data(i);
| ^^^^^^^^^^^^^^^ assignment to borrowed `*data` occurs here
16 | let condition = f(data);
| -------
| | |
| | borrow of `*data` occurs here
| argument requires that `*data` is borrowed for `'a`
error[E0499]: cannot borrow `*data` as mutable more than once at a time
--> src/main.rs:20:17
|
10 | fn foo<'a, F>(data: &'a mut Data, f: F)
| -- lifetime `'a` defined here
...
16 | let condition = f(data);
| -------
| | |
| | first mutable borrow occurs here
| argument requires that `*data` is borrowed for `'a`
...
20 | i = data.generate_new();
| ^^^^ second mutable borrow occurs here
Compiler says the data is borrowed because of calling a function with it, but the function f just returns a bool value, not reference of anything. Therefore I think the borrowing of data should be ended when the returned bool value has assigned to a local variable and line 15 or 20 should be fine.
It would be grateful if someone explain what is going on and what I should do to avoid this error.
The problem is the bounds on F require that it borrow data for the full lifetime 'a. The fact that the return value doesn't contain any lifetimes is irrelevant.
Your problem lies in the function signature of foo. Note that when you don’t try to manually specify any lifetimes, it compiles fine.
fn foo<F>(data: &mut Data, f: F)
where F: Fn(&mut Data) -> bool
{
let mut i = 1;
loop {
*data = Data(i);
let condition = f(data);
if condition {
return;
} else {
i = data.generate_new();
}
}
}
The problem is that you artificially restrict the signature by adding 'a manually and using it in multiple places, including the argument of f: F. This means that the compiler assumes that f needs to borrow it argument for the whole lifetime of the data reference. Since this borrow is also mutable, it can’t work more than once, but it’s in a loop, hence the error.
To understand how eliding the lifetime helped above, let’s see what the above code is desugared to:
fn foo<'a, F>(data: &'a mut Data, f: F)
where F: for<'b> Fn(&'b mut Data) -> bool
{
let mut i = 1;
loop {
*data = Data(i);
let condition = f(data);
if condition {
return;
} else {
i = data.generate_new();
}
}
}
The idea is that this correct signature of foo requires f to be applicable to &'b mut Data references of any lifetime. Each call of f can get a different lifetime here (and it does, as it’s a new re-borrow of data in a different loop iteration).
Edit: I also wanted to point out that you consistently mis-spelled “borrowing”. I’ve already fixed the title for you, too.