rust - 为什么编译器告诉我考虑使用 `let` 绑定(bind)?

标签 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 绑定(bind)”——但我已经是:

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 ,但不涉及将表达式分解为多个语句,因此我认为问题不相同。

最佳答案

问题是 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按值(value),所以 Iter被消费了,我们得到一个 std::iter::Peekable作为返回,再次持有对切片的引用。
  • Peekable然后绑定(bind)到变量 vals ,它一直存在到函数结束。
  • 暂持原Vec<i8> , 其元素 Peekable指的是,现在死了。哎呀。这是借来的值(value)不够长。

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

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

我想这就是故事。然而,仍然让我感到困惑的是,为什么即使没有名字,临时工也不会活得更久。 Rust 引用说,“一个临时对象的生命周期等于任何指向它的引用的最大生命周期。”但这里显然不是这种情况。

关于rust - 为什么编译器告诉我考虑使用 `let` 绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28893183/

相关文章:

RuSTLings Traits4.rs 为什么 impl Trait 语法有效,但特征绑定(bind)语法或 where 子句不起作用

rust - 四处移动对象然后调用消耗对象自身的方法会产生 "cannot move out of borrowed content"

rust - 无法在另一种方法中使用迭代器,因为 "borrow might be used when that temporary is dropped"

rust - 如何注释此 Rust/Calloop 回调代码的生命周期?

rust - 不使用标准库时如何迭代搜索并从列表中删除

unicode - char::is_digit 和 char::is_numeric 有什么区别?

rust - 特征对象和特征的直接实现者的特征实现

rust - 提取结构生成宏中字段出现的索引

alias - Rust 中的类型别名

rust - 是否可以在 stdin.lines() 中间执行另一次读取?