Reputation: 2515
struct Foo<'a> {
bytes: &'a mut [u8],
}
impl<'a> Foo<'a> {
fn bar<'b>(&'b mut self) {
self.bytes = &mut self.bytes[1..];
}
}
fn baz<'a, 'b>(foo: &'b mut Foo<'a>) {
println!("baz!");
for _ in 0..3 {
foo.bar();
}
}
Also here in a Rust Playground.
This results in the following error traceback:
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:12:27
|
12 | self.bytes = &mut self.bytes[1..];
| ^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
--> src/main.rs:11:12
|
11 | fn bar<'b>(&'b mut self) {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:27
|
12 | self.bytes = &mut self.bytes[1..];
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:10:6
|
10 | impl<'a> Foo<'a> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:22
|
12 | self.bytes = &mut self.bytes[1..];
| ^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0495`.
error: could not compile `playground` due to previous error
I'm looking to change the function signatures of bar
/ baz
to get this to compile. My understanding was that I needed to specify lifetime bounds on 'a
& 'b
and it would work, but I get different errors for both 'b: 'a
and 'a: 'b
in either/both functions.
I've also looked through ~10 other "mutable borrow in loop" questions, but I don't understand the answers well enough to apply them to my problem, so even if this is a duplicate I'd appreciate an answer relevant to this toy example specifically.
Any help is appreciated!
Upvotes: 0
Views: 279
Reputation: 822
The problem here is the borrow happens through 'b
. ('b
and 'a
are disjoint). The compiler wants you to guarantee the reference 'b
needs to be atleast as long as 'a
. So we should look for a way where 'b
isn't involved when (re)borrowing the slice, as 'b
is considered to be valid only for the function call duration. There is no return
or an "outgoing" lifetime from the call.
You can use the std::mem::*
functions to achieve this
Upvotes: 3
Reputation: 8484
@vikram2784's solution works, but can be expressed a bit more concisely by only replacing bytes
, not the entire Foo
:
impl<'a> Foo<'a> {
fn bar(&mut self) {
let tmp = &mut [][..];
let bytes = std::mem::replace(&mut self.bytes, tmp);
self.bytes = &mut bytes[1..];
}
}
This pattern is also easier to use if Foo
contains some additional fields that don't have obvious default values.
One thing to note about this kind of solution: If the bytes[1..]
panics, the empty temporary will be left in place. Here, the only reason for a panic I can think of is bytes
being empty, so it won't matter, but depending on the situation, you may get bitten by it.
Upvotes: 6