Here is the code:
struct Buffer<'a> {
buf: &'a mut Vec<u8>,
pos: usize,
}
impl<'a> Buffer<'a> {
fn new(v: &mut Vec<u8>) -> Buffer {
Buffer { buf: v, pos: 0 }
}
fn read_bytes(&mut self) -> &'a [u8] {
self.pos += 3;
&self.buf[self.pos - 3..self.pos]
}
}
fn print(b1: &[u8], b2: &[u8]) {
println!("{:#?} {:#?}", b1, b2)
}
fn main() {
let mut v = vec![1, 2, 3, 4, 5, 6];
let mut buf = Buffer::new(&mut v);
let b1 = buf.read_bytes();
}
//
Then I got a compile error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:406:4
|
406 | &self.buf[self.pos - 3..self.pos]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/main.rs:403:16
|
403 | fn read_bytes(&mut self) -> &'a [u8] {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:406:4
|
406 | &self.buf[self.pos - 3..self.pos]
| ^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:398:6
|
398 | impl<'a> Buffer<'a> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:406:3
|
406 | &self.buf[self.pos - 3..self.pos]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0495`.
However, when I tried to make buf
immutable, the compiler did't report the error anymore, like this:
struct Buffer<'a> {
buf: &'a Vec<u8>,
pos: usize,
}
impl<'a> Buffer<'a> {
fn new(v: &mut Vec<u8>) -> Buffer {
Buffer { buf: v, pos: 0 }
}
fn read_bytes(&mut self) -> &'a [u8] {
self.pos += 3;
&self.buf[self.pos - 3..self.pos]
}
}
fn print(b1: &[u8], b2: &[u8]) {
println!("{:#?} {:#?}", b1, b2)
}
fn main() {
let mut v = vec![1, 2, 3, 4, 5, 6];
let mut buf = Buffer::new(&mut v);
let b1 = buf.read_bytes();
}
According to the lifetime elision rules in rust-lang book:
The compiler uses three rules to figure out what lifetimes references have when there aren’t explicit annotations. The first rule applies to input lifetimes, and the second and third rules apply to output lifetimes. If the compiler gets to the end of the three rules and there are still references for which it can’t figure out lifetimes, the compiler will stop with an error. These rules apply to fn definitions as well as impl blocks.
The first rule is that each parameter that is a reference gets its own lifetime parameter. In other words, a function with one parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a function with two parameters gets two separate lifetime parameters: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on.
The second rule is if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32.
The third rule is if there are multiple input lifetime parameters, but one of them is &self or &mut self because this is a method, the lifetime of self is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary.
I can't tell what's the difference here. IMOP both lifetime elision should work. Can anyone HELP me. Thanks a lot.