问题
What is my error and how to fix it?
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let mut vals = get_m().iter().peekable();
println!("Saw a {:?}", vals.peek());
}
(playground)
The compiler's error suggests "consider using a let
binding" — but I already am:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:6:45
|
6 | let mut vals = get_m().iter().peekable();
| ------- ^ temporary value dropped here while still borrowed
| |
| temporary value created here
7 | println!("Saw a {:?}", vals.peek());
8 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
This is obviously a newbie question -- though I thought I'd written enough Rust at this point that I had a handle on the borrow checker... apparently I haven't.
This question is similar to Using a `let` binding to increase value lifetime, but doesn't involve breaking down an expression into multiple statements, so I don't think the problem is identical.
回答1:
The problem is that the Peekable
iterator lives to the end of the function, but it holds a reference to the vector returned by get_m
, which only lasts as long as the statement containing that call.
There are actually a lot of things going on here, so let's take it step by step:
get_m
allocates and returns a vector, of typeVec<i8>
.- We make the call
.iter()
. Surprisingly,Vec<i8>
has noiter
method, nor does it implement any trait that has one. So there are three sub-steps here:- Any method call checks whether its
self
value implements theDeref
trait, and applies it if necessary.Vec<i8>
does implementDeref
, so we implicitly call itsderef
method. However,deref
takes itsself
argument by reference, which means thatget_m()
is now an rvalue appearing in an lvalue context. In this situation, Rust creates a temporary to hold the value, and passes a reference to that. (Keep an eye on this temporary!) - We call
deref
, yielding a slice of type&[i8]
borrowing the vector's elements. - This slice implements the
SliceExt
trait, which does have aniter
method. Finally! Thisiter
also takes itsself
argument by reference, and returns astd::slice::Iter
holding a reference to the slice.
- Any method call checks whether its
- We make the call
.peekable()
. As before,std::slice::Iter
has nopeekable
method, but it does implementIterator
;IteratorExt
is implemented for everyIterator
; andIteratorExt
does have apeekable
method. This takes itsself
by value, so theIter
is consumed, and we get astd::iter::Peekable
back in return, again holding a reference to the slice. - This
Peekable
is then bound to the variablevals
, which lives to the end of the function. - The temporary holding the original
Vec<i8>
, to whose elements thePeekable
refers, now dies. Oops. This is the borrowed value not living long enough.
But the temporary dies there only because that's the rule for temporaries. If we give it a name, then it lasts as long as its name is in scope:
let vec = get_m();
let mut peekable = vec.iter().peekable();
println!("Saw a {:?}", vals.peek());
I think that's the story. What still confuses me, though, is why that temporary doesn't live longer, even without a name. The Rust reference says, "A temporary's lifetime equals the largest lifetime of any reference that points to it." But that's clearly not the case here.
回答2:
This is happening because you are trying to run your .iter().peekable()
on the actual vector inside of get_m()
, which is getting re-referenced by vals
.
Basically, you want something like this:
fn get_m() -> Vec<i8> {
vec![1, 2, 3]
}
fn main() {
let vals = get_m();
let mut val = vals.iter().peekable();
println!("Saw a {:?}", val.peek());
}
(Playground)
Result:
Saw a Some(1)
来源:https://stackoverflow.com/questions/28893183/why-does-the-compiler-tell-me-to-consider-using-a-let-binding-when-i-already