Rust中为什么trait对象调用enumerate()时未被转移所有权?
Rust 迭代器可变引用所有权问题解答
问题复现
你提供的代码如下:
fn dump(iter: &mut dyn Iterator<Item=String>) { for (i, v) in iter.enumerate() { println!("{} {}", i, v); } for v in iter { println!("{}", v); } } #[test] fn test_trait() { let v = vec!["a".to_string(), "b".to_string(), "c".to_string()]; let mut iter = v.into_iter(); dump(&mut iter); }
运行测试的输出为:
running 1 test
0 a1 b2 c
test test_trait ... ok
核心原因
该现象的本质是 Rust 标准库对迭代器做了泛型自动实现:所有实现了 Iterator trait 的类型,它的可变引用 &mut I 也会自动实现 Iterator trait,实现逻辑大致如下:
impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I { type Item = I::Item; fn next(&mut self) -> Option<I::Item> { (**self).next() } }
当你对 &mut dyn Iterator 类型的 iter 调用 enumerate() 时:
enumerate要求按值传递self入参,这里实际被转移走的是iter这个可变引用的临时副本,不是原iter变量本身的所有权- 临时副本被
enumerate生成的迭代器消费,整个过程不会影响原iter变量的所有权 - 所以第一个循环结束后,原
iter变量依然是可用状态,第二个for循环可以正常编译通过
补充说明
输出中第二个 for 循环没有打印任何内容,是因为第一个循环已经把迭代器内的所有元素全部遍历完了,第二个循环执行时迭代器已经是空状态,不会进入循环体。
内容的提问来源于stack exchange,提问作者shimoo
相关产品推荐
相关产品推荐

