问题描述
我正在观看 Rust 讲座,看到我想到了两种迭代向量的方法。我可以遍历“向量本身”或“iter() 方法”。你能告诉我这里有什么区别吗?
fn call(from: &mut Vec<i32>,to: &mut Vec<i32>) {
for e in from.iter() {
to.push(*e);
}
for e in from {
to.push(*e);
}
}
fn printvec(from: & Vec<i32>) {
for e in from {
print!("{} ",e);
}
println!("");
}
fn main() {
let mut v1 = vec![1,2,3];
let mut v2 = vec![1,3];
call(&mut v1,&mut v2);
printvec(&v1);
printvec(&v2);
}
解决方法
你能告诉我这里有什么区别吗?
这里与 Stargateur 指出的没有区别。要知道发生了什么,您只需遵循 white rabbit trait 实现:Rust 的 for
循环“简单地”调用“RHS”上的 IntoIterator
。现在如果我们往下走 the list of implementors
我们可以看到an implementation for &Vec
它本身没有记录,而是 looking at the code it just calls self.iter()
,所以在这里我们确实确认了 Stargateur 是正确的,&Vec
和 Vec::iter
做完全相同的事情
Vec::iter
文档有点简洁,但它链接到 std::slice::Iter
,它是“不可变切片迭代器”,本身不一定非常有用但是特征实现非常清楚 >
impl<'a,T> Iterator for Iter<'a,T> {
type Item = &'a T
}
所以 Vec<T>::iter
-> Iter<T>
-> Iterator<Item=&a>
,意思是当你 .iter()
一个向量(或者你迭代一个 &Vec
)时,你迭代 对项目的不可变引用。并且由于 iter
需要 &self
(并且 &Vec
显然是一个引用)这也意味着迭代仅借用向量,所以一旦你完成迭代向量仍然保持不变。
&mut Vec
和 Vec::iter_mut
虽然你没有提到它是第二个迭代器,但它与上面的类似,只是它产生一个 std::slice::IterMut
impl<'a,T> Iterator for IterMut<'a,T> {
type Item = &'a mut T
}
因此,它不会产生对项目的不可变引用,而是产生可变的引用,这意味着您可以就地修改项目,例如增加它们,很酷。
Vec
itself
所以我们来到这里,如果你扩展定义,你会看到本质上是这样的:
impl<T> IntoIterator for Vec<T> {
type Item = T
type IntoIter = IntoIter<T,A>
pub fn into_iter(self) -> IntoIter<T,A>
创建一个消费迭代器,即将每个值移出向量(从开始到结束)。调用此向量后,将无法使用该向量。
这是不言自明的:如果您直接对 Vec
进行迭代,它会消耗向量,这意味着您之后将无法使用它.
然而,作为回报,它将向量项的所有权转移到迭代器中,这提供了更大的灵活性。
,'label: for PATTERN in iter_expr {
/* loop body */
}
相当于
{
let result = match IntoIterator::into_iter(iter_expr) {
mut iter => 'label: loop {
let mut next;
match Iterator::next(&mut iter) {
Option::Some(val) => next = val,Option::None => break,};
let PATTERN = next;
let () = { /* loop body */ };
},};
result
}
for 循环之间的区别在于,在一个循环中,iter_expr
是 from
,而在另一个循环中是 from.iter()
。 IntoIterator
是这样实现的,用于向量引用:
impl<'a,T,A: Allocator> IntoIterator for &'a Vec<T,A> {
type Item = &'a T;
type IntoIter = slice::Iter<'a,T>;
fn into_iter(self) -> slice::Iter<'a,T> {
self.iter()
}
}
请注意,它正在调用 self.iter()
,因此此迭代器与您从 from.iter()
for 循环中获得的迭代器没有区别。