for x in v 与 for x in &v 看起来只差一个 &,含义却完全不同。这篇用元素类型的真实打印、所有权的编译报错、以及为自己的集合补齐三种 impl,把 IntoIterator 的三种遍历讲清楚。
源码:
1 | fn tn<T>(_: &T) -> &'static str { std::any::type_name::<T>() }
2 | fn main() {
3 | let mut v = vec![String::from("a"), String::from("b")];
4 | for x in &v { println!("for x in &v → x 的类型 {}", tn(&x)); break; }
5 | for x in &mut v { println!("for x in &mut v → x 的类型 {}", tn(&x)); x.push('!'); }
6 | for x in v.clone() { println!("for x in v → x 的类型 {}", tn(&x)); break; }
7 | println!("修改之后 v = {:?}", v);
8 | }
编译:成功
运行(退出码 0):
for x in &v → x 的类型 &alloc::string::String
for x in &mut v → x 的类型 &mut alloc::string::String
for x in &mut v → x 的类型 &mut alloc::string::String
for x in v → x 的类型 alloc::string::String
修改之后 v = ["a!", "b!"]for 循环的底层展开见for 循环如何转换成 Iterator。
源码:
1 | fn main() {
2 | let v = vec![1, 2, 3];
3 | for x in v { println!("{x}"); }
4 | println!("{:?}", v);
5 | }
编译:失败
error[E0382]: borrow of moved value: `v`
--> <实验目录>/src/u54b.rs:4:22
|
2 | let v = vec![1, 2, 3];
| - move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
3 | for x in v { println!("{x}"); }
| - `v` moved due to this implicit call to `.into_iter()`
4 | println!("{:?}", v);
| ^ value borrowed here after move
|
note: `into_iter` takes ownership of the receiver `self`, which moves `v`
--> <rust 标准库源码>/library/core/src/iter/traits/collect.rs:312:18
|
312 | fn into_iter(self) -> Self::IntoIter;
| ^^^^
help: consider iterating over a slice of the `Vec<i32>`'s content to avoid moving into the `for` loop
|
3 | for x in &v { println!("{x}"); }
| +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0382`. 源码:
1 | struct Bag { items: Vec<i32> }
2 | impl IntoIterator for Bag { type Item = i32; type IntoIter = std::vec::IntoIter<i32>; fn into_iter(self) -> Self::IntoIter { self.items.into_iter() } }
3 | impl<'a> IntoIterator for &'a Bag { type Item = &'a i32; type IntoIter = std::slice::Iter<'a, i32>; fn into_iter(self) -> Self::IntoIter { self.items.iter() } }
4 | impl<'a> IntoIterator for &'a mut Bag { type Item = &'a mut i32; type IntoIter = std::slice::IterMut<'a, i32>; fn into_iter(self) -> Self::IntoIter { self.items.iter_mut() } }
5 | fn main() {
6 | let mut bag = Bag { items: vec![1, 2, 3] };
7 | for x in &bag { print!("读 {x} "); }
8 | println!();
9 | for x in &mut bag { *x *= 10; }
10 | for x in &bag { print!("读 {x} "); }
11 | println!();
12 | let total: i32 = bag.into_iter().sum(); // 消费 bag
13 | println!("消费后求和 = {total}");
14 | }
编译:成功
运行(退出码 0):
读 1 读 2 读 3
读 10 读 20 读 30
消费后求和 = 60
编译:失败
error[E0277]: `&Bag` is not an iterator
--> <实验目录>/src/u54d.rs:2:56
|
2 | fn main() { let bag = Bag { items: vec![1] }; for x in &bag { println!("{x}"); } }
| ^^^^ `&Bag` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&Bag`
= note: required for `&Bag` to implement `IntoIterator`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.Iterator 本身见Iterator Trait。
源码:
1 | use std::collections::BTreeMap;
2 | fn tn<T>(_: &T) -> &'static str { std::any::type_name::<T>() }
3 | fn main() {
4 | let arr = [String::from("x"), String::from("y")];
5 | for s in arr { println!("数组 for s in arr → {}", tn(&s)); break; }
6 | let mut m = BTreeMap::new(); m.insert("k", 1);
7 | for kv in &m { println!("for kv in &m → {}", tn(&kv)); }
8 | for kv in m.clone() { println!("for kv in m → {}", tn(&kv)); }
9 | for v in m.values_mut() { *v += 1; }
10 | println!("values_mut 之后 {:?}", m);
11 | }
编译:成功
运行(退出码 0):
数组 for s in arr → alloc::string::String
for kv in &m → (&&str, &i32)
for kv in m → (&str, i32)
values_mut 之后 {"k": 2}