5

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

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

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

操场

编译器的错误提示“考虑使用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,但不涉及将表达式分解为多个语句,所以我认为问题并不相同。

4

2 回答 2

9

问题是Peekable迭代器一直存在到函数的末尾,但它持有对由返回的向量的引用get_m,它只持续与包含该调用的语句一样长。

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

  • get_m分配并返回一个向量,类型为Vec<i8>
  • 我们打电话.iter()。令人惊讶的是,Vec<i8>它没有iter方法,也没有实现任何具有方法的特征。所以这里有三个子步骤:
    • 任何方法调用都会检查其self值是否实现了Deref特征,并在必要时应用它。Vec<i8>确实实现Deref了,所以我们隐式调用它的deref方法。但是,通过引用deref获取其self参数,这意味着它get_m()现在是出现在左值上下文中的右值。在这种情况下,Rust 创建了一个临时值来保存该值,并传递一个对它的引用。(留意这个临时的!)
    • 我们调用deref,产生一个&[i8]借用向量元素的类型切片。
    • 这个 slice 实现了SliceExttrait,它确实有一个iter方法。最后!这iterself通过引用获取它的参数,并返回一个std::slice::Iter对切片的引用。
  • 我们打电话.peekable()。和以前一样,std::slice::Iter没有peekable方法,但它确实实现了IteratorIteratorExt为每个实施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 引用说:“临时的生命周期等于指向它的任何引用的最大生命周期。” 但这显然不是这里的情况。

于 2015-03-06T11:02:59.290 回答
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());
}

游乐场

结果:

Saw a Some(1)
于 2015-03-06T06:29:38.353 回答