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

时间:2015-03-06 06:03:10

标签: 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());
}

playground

编译器的错误表明“考虑使用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

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

此问题与Using a `let` binding to increase value lifetime类似,但不涉及将表达式分解为多个语句,因此我认为问题不一致。

2 个答案:

答案 0 :(得分: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方法。最后!此iter也通过引用获取其self参数,并返回一个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());

我认为这就是故事。然而,让我感到困惑的是,即使没有名字,临时也不会延长寿命的原因。 Rust引用说,&#34;临时生命周期等于指向它的任何引用的最大生命周期。&#34;但这显然不是这种情况。

答案 1 :(得分: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());
}

Playground

结果:

Saw a Some(1)