Rust中两种Vector遍历方式的区别及相关报错疑问
Rust Vector两种遍历写法的区别解析
请问以下两种遍历Rust Vector的写法有什么区别?
let names = vec!["Bob", "Frank", "Ferris"]; for name in names.iter() { println!("Hello {}", name); }
let names = vec!["Bob", "Frank", "Ferris"]; for name in &names { println!("Hello {}", name); }
两者运行起来行为看起来完全一致,我是不是忽略了什么关键点?
我不确定这是不是另一个问题的重复——那个问题问的是直接遍历names和遍历names.iter()的区别。但如果是重复问题的话,为什么我必须在names前面加&才能避免下面这个报错?
Compiling playground v0.0.1 (/playground) error[E0382]: borrow of moved value: `names` --> src/main.rs:15:17 | 2 | let names = vec!["Bob", "Frank", "Ferris"]; | ----- move occurs because `names` has type `Vec<&str>`, which does not implement the `Copy` trait ... 12 | for name in names { | ----- `names` moved due to this implicit call to `.into_iter()` ... 15 | for name in names.iter() { | ^^^^^^^^^^^^ value borrowed here after move | note: `into_iter` takes ownership of the receiver `self`, which moves `names` --> /rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/core/src/iter/traits/collect.rs:262:18 = note: borrow occurs due to deref coercion to `[&str]` help: consider iterating over a slice of the `Vec<&str>`'s content to avoid moving into the `for` loop | 12 | for name in &names { | + For more information about this error, try `rustc --explain E0382`. error: could not compile `playground` due to previous error
本质等价的两种写法
你看到的这两种写法本质上完全等价,背后是Rust的语法糖和自动解引用机制在起作用:
names.iter()是显式调用Vec的iter()方法,返回一个不可变引用迭代器,遍历过程中每个元素是&T类型(这里T是&str,所以元素是&&str,打印时会自动解引用)。&names是对Vec取不可变引用,由于&Vec<T>可以自动解引用为&[T](切片),而切片&[T]实现了IntoIteratortrait,其迭代器同样产生&T类型的元素,和iter()的结果完全一致。
为什么直接遍历names会报错?
直接写for name in names时,调用的是Vec<T>自身的IntoIterator实现——这个实现会转移整个Vec的所有权,把Vec转换成一个消耗型迭代器。遍历完成后,names变量已经被移动,无法再被后续代码使用(比如报错里的names.iter()调用)。
而names.iter()和&names都是基于不可变引用的遍历,不会转移names的所有权,遍历结束后你仍然可以正常操作这个Vec变量。
总结
names.iter()与&names是等价写法,均为不可变引用遍历,不消耗原Vec的所有权- 直接遍历
names会消耗所有权,遍历后原变量无法复用
内容的提问来源于stack exchange,提问作者zmunk
相关产品推荐
相关产品推荐

