一个关于迭代器和所有权的问题?

我是 Rust 的新手,跟着 Rust 权威指南和视频学到了并发章节,有个例子遇到了点问题:

use std::{sync::mpsc, thread, time::Duration};

fn main() {
  let (tx, rx) = mpsc::channel();

  thread::spawn(move || {
    let v = vec![
      String::from("Hello"),
      String::from("I'm XiaoMing"),
      String::from("I come from China"),
      String::from("Nice to meet you"),
    ];

    for s in v.iter() {
      tx.send(s).unwrap();
      thread::sleep(Duration::from_millis(300));
    }
  });

  for msg in rx {
    println!("{}", msg);
  }
}

我的 VSCode 在 v.iter() 处报了错:

`v` does not live long enough
borrowed value does not live long enoughrustcE0597
main.rs(18, 3): `v` dropped here while still borrowed
main.rs(4, 8): lifetime `'1` appears in the type of `tx`
main.rs(15, 7): argument requires that `v` is borrowed for `'1`

我知道 for in 循环会取得迭代器的所有权,iter 方法的第一个参数是 &self,它没有取得 v 的所有权,迭代器的所有权转移了,为什么 v 会失效?

另外如果我不调用 iter 直接用 v 去循环就能通过,这两种有什么区别吗?

====== 补充下在 rust playground 里的错误信息,可能有帮助:

   Compiling playground v0.0.1 (/playground)
error[E0597]: `v` does not live long enough
  --> src/main.rs:14:14
   |
4  |   let (tx, rx) = mpsc::channel();
   |        -- lifetime `'1` appears in the type of `tx`
...
14 |     for s in v.iter() {
   |              ^^^^^^^^ borrowed value does not live long enough
15 |       tx.send(s).unwrap();
   |       ---------- argument requires that `v` is borrowed for `'1`
...
18 |   });
   |   - `v` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
阅读 2.5k
1 个回答

for s in v ,s 拿到了 v 中元素的所有权。元素就不再被 v 拥有了。这样元素的 life 也就与 v 无关了。此时 send 的参数不是引用,没有 life 的问题。

for s in v.iter() ,这是一个只读迭代,s 没有拿到 v 中元素的所有权,只是一个引用。tx.send 拿到一个这个引用,他需要引用的 life 比 tx 更长(或者一样长)。但是这里,sv 中元素引用的 life 是与 v 一样长的,在作为 spawn 的参数的函数外,v 的 life 就结束了,但是 tx 还在,这是不行的。 s 是比 tx 后声明的,所以 lifetime 会先先比 tx 先终止,life 比 tx 短。

=============

可以看另一个例子:

use std::sync::mpsc;

fn main() {
  let (tx, _) = mpsc::channel();
  let zz = String::from("xx");
  tx.send(&zz);
}
   Compiling playground v0.0.1 (/playground)
error[E0597]: `zz` does not live long enough
 --> src/main.rs:6:11
  |
6 |   tx.send(&zz);
  |           ^^^ borrowed value does not live long enough
7 | }
  | -
  | |
  | `zz` dropped here while still borrowed
  | borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `Sender`
  |
  = note: values in a scope are dropped in the opposite order they are defined

For more information about this error, try `rustc --explain E0597`.
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进