为何(&mut iter).take(n)不获取iter所有权?Rust迭代器疑问
Rust迭代器take在闭包中的所有权问题解析
先看代码示例:
fn main() { let my_vec = vec![1,2,3,4,5,6,7,8]; let mut pair: Vec<Vec<u8>> = vec![vec![], vec![]]; let mut my_vec_iter = my_vec.into_iter(); // pair.iter_mut().for_each(|v| v.append(&mut my_vec_iter.take(4).collect())); // error[E0507]: cannot move out of `my_vec_iter`, a captured variable in an `FnMut` closure let my_ref = &mut my_vec_iter; pair.iter_mut().for_each(|v| v.append(&mut my_ref.take(4).collect())); println!("{:?}", pair); }
问题核心
注释代码报错的原因是:take(self)需要拿走迭代器的所有权,但for_each的闭包是FnMut类型——它会被调用多次(这里是2次,对应pair里的两个元素),第一次调用闭包时就把my_vec_iter移动走了,第二次调用时就没有可移动的变量了,因此编译报错。
而改成用&mut my_vec_iter的版本能正常运行,本质原因在于Rust的一个隐含实现。
本质原因:迭代器的 blanket 实现
Rust 为所有实现了Iterator trait的类型I,自动为&mut I(迭代器的可变引用)也实现了Iterator trait。这个实现相当于一个“代理”:它的next方法会通过可变引用调用原迭代器的next,不会拿走原迭代器的所有权。
当你在&mut I上调用take方法时:
- 调用的是这个代理迭代器(
&mut I)的take,而take是Iteratortrait的默认方法,它接收的self是&mut I类型(也就是代理迭代器的所有权)。 - 此时返回的
Take适配器持有是&mut I(原迭代器的可变引用),而不是原迭代器本身的所有权。 - 闭包每次调用时,只是借用
my_ref(原迭代器的可变引用)来创建这个代理迭代器,用完之后还给外部,因此可以被多次调用,不会出现所有权移动的问题。
简单总结:
- 直接用原迭代器调用
take:拿走迭代器所有权,只能用一次。 - 用迭代器的可变引用调用
take:只借用原迭代器,调用多少次都不会移动原迭代器的所有权,符合FnMut闭包的要求。
内容的提问来源于stack exchange,提问作者Chowlett
相关产品推荐
相关产品推荐

