为什么编译器告诉我考虑使用`let`绑定"?

Bos*_*osh 4 rust borrow-checker

我的错误是什么以及如何解决?

fn get_m() -> Vec<i8> {
    vec![1, 2, 3]
}

fn main() {
    let mut vals = get_m().iter().peekable();
    println!("Saw a {:?}", vals.peek());
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

编译器的错误表明"考虑使用let绑定" - 但我已经:

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
Run Code Online (Sandbox Code Playgroud)

这显然是一个新手问题 - 虽然我认为我已经写了足够的Rust,我已经掌握了借用检查器...显然我没有.

这个问题类似于使用`let`绑定来增加值生命周期,但不涉及将表达式分解为多个语句,所以我不认为问题是相同的.

Jim*_*ndy 7

问题是Peekable迭代器存在于函数的末尾,但它包含对返回的向量的引用,该引用get_m只持续包含该调用的语句.

实际上这里发生了很多事情,所以让我们一步一步来看:

  • get_m分配并返回类型的向量Vec<i8>.
  • 我们打电话.iter().令人惊讶的是,Vec<i8>没有iter方法,也没有实现任何特征.所以这里有三个子步骤:
    • 任何方法调用都会检查其self值是否实现了Deref特征,并在必要时应用它.Vec<i8>确实实现了Deref,所以我们隐式调用它的deref方法.但是,通过引用deref获取其self参数,这意味着get_m()现在是左值上下文中出现的右值.在这种情况下,Rust会创建一个临时值来保存该值,并将引用传递给该值.(留意这暂时!)
    • 我们调用deref,产生一个&[i8]借用向量元素的片段.
    • 这片实现SliceExt特质,这确实有一个iter方法.最后!这iterself通过引用获取其参数,并返回std::slice::Iter持有对切片的引用.
  • 我们打电话.peekable().和以前一样,std::slice::Iter没有peekable方法,但确实实现了Iterator; IteratorExt为每一个实施Iterator; 并IteratorExt 确实有一个peekable方法.这取了它self的值,所以Iter消耗了,我们得到一个std::iter::Peekable返回,再次保持对切片的引用.
  • Peekable随后绑定到变量vals,其居住的函数的末尾.
  • 暂时持有原件Vec<i8>,其Peekable所指的元件现在已经死亡.哎呀.这是借来的价值不够长.

但临时死在那里只是因为这是临时的规则.如果我们给它一个名字,那么只要名称在范围内,它就会持续:

let vec = get_m();
let mut peekable = vec.iter().peekable();
println!("Saw a {:?}", vals.peek());
Run Code Online (Sandbox Code Playgroud)

我认为这就是故事.然而,让我感到困惑的是,即使没有名字,临时也不会延长寿命的原因.Rust参考文献说:"临时生命周期等于任何指向它的参考文献的最大生命周期." 但这显然不是这里的情况.


小智 5

发生这种情况是因为你正试图运行.iter().peekable()在内部的实际载体get_m(),这是越来越通过重新引用vals.

基本上,你想要这样的东西:

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());
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

结果:

Saw a Some(1)
Run Code Online (Sandbox Code Playgroud)