为何into_iter()返回T而非&mut T?Rust迭代器类型疑问
Rust中into_iter()产出类型与std::mem::swap的类型不匹配问题解析
问题描述
我看到Stack Overflow上提到,into_iter()返回的迭代器会根据上下文产出T、&T或&mut T类型的值。但我写的Rust代码里,用into_iter()产出的是T类型,而std::mem::swap()需要&mut T作为参数,导致类型不匹配错误。我知道换成iter_mut()能解决编译问题,但想搞清楚背后的原因。
代码示例
fn main() { let mut first_list = vec![String::from("abcde"), String::from("fghij"), String::from("klmno"), String::from("pqrst"), String::from("uvwxy")]; let second_list: Vec<String> = first_list.into_iter().rev().map(|x| { let mut d = String::from(""); std::mem::swap(x, &mut d); d }).collect::<Vec<String>>(); assert_eq!(vec![String::from("uvwxy"), String::from("pqrst"), String::from("klmno"), String::from("fghij"), String::from("abcde")], second_list); assert_eq!(vec![0, 0, 0, 0, 0], vec![first_list[0].len(), first_list[1].len(), first_list[2].len(), first_list[3].len(), first_list[4].len()]); }
错误信息
error[E0308]: mismatched types --> src/main.rs:5:28 | 5 | std::mem::swap(x, &mut d); | -------------- ^ expected `&mut String`, found `String` | | | arguments to this function are incorrect | = note: expected mutable reference `&mut String` found struct `String` note: function defined here --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/mod.rs:732:14 | 732 | pub const fn swap<T>(x: &mut T, y: &mut T) { | ^^^^ help: consider mutably borrowing here | 5 | std::mem::swap(&mut x, &mut d); | ++++ For more information about this error, try `rustc --explain E0308`.
原因解析
核心:into_iter()的行为由调用者类型决定
into_iter()的产出类型并非凭空由上下文决定,而是完全取决于调用它的对象:
- 当对拥有所有权的
Vec<T>(比如代码里的first_list)调用into_iter()时,这个迭代器的作用是消费整个原容器——它会把容器内每个元素的所有权转移出来,因此迭代产出的是T类型(这里就是String)。此时你拿到的x是完整的String对象,不是引用。 - 只有当调用者是
&Vec<T>或&mut Vec<T>时,into_iter()才会产出引用类型:- 对
&Vec<T>调用into_iter(),等价于iter(),产出&T; - 对
&mut Vec<T>调用into_iter(),等价于iter_mut(),产出&mut T。
- 对
你的代码里是直接对first_list(所有权实例)调用into_iter(),所以迭代器必然产出String,而std::mem::swap()要求两个&mut T参数,自然会出现类型不匹配。
为什么iter_mut()能解决问题?
iter_mut()是针对&mut Vec<T>的方法(或通过语法糖自动生成可变引用),它返回的迭代器会产出&mut T类型的可变引用——每个元素都是原容器中元素的可变引用,刚好符合std::mem::swap()的参数要求。
额外说明:代码逻辑的冗余点
其实这里用swap完全没必要:into_iter()已经把first_list里的String所有权转移给了x,直接返回x就能得到同样的结果。而且原first_list会因为被消费而变成空容器,后面的assert_eq!会因为访问空容器索引而panic,这点需要注意。
解决办法
- 如果需要保留原
first_list并将其中元素置空,使用iter_mut():
这样let second_list: Vec<String> = first_list.iter_mut().rev().map(|x| { let mut d = String::from(""); std::mem::swap(x, &mut d); d }).collect();first_list里的元素会被置空,second_list拿到反转后的字符串。 - 如果不需要保留
first_list,直接简化代码:
这行代码就能得到反转后的let second_list: Vec<String> = first_list.into_iter().rev().collect();Vec<String>,原first_list会被自动销毁。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

