我正在做Rust示例教程,其中包含以下代码片段:
// Vec example
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`. Destructure to `i32`.
println!("2 in vec1: {}", vec1.iter() .any(|&x| x == 2));
// `into_iter()` for vecs yields `i32`. No destructuring required.
println!("2 in vec2: {}", vec2.into_iter().any(| x| x == 2));
// Array example
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`.
println!("2 in array1: {}", array1.iter() .any(|&x| x == 2));
// `into_iter()` for arrays unusually yields `&i32`.
println!("2 in array2: {}", array2.into_iter().any(|&x| x == 2));
Run Code Online (Sandbox Code Playgroud)
我很困惑 - 对于Vec从iteryield引用返回的迭代器和从into_iteryield值返回的迭代器,但是对于数组,这些迭代器是相同的吗?
这两种方法的用例/ API是什么?
Mat*_* M. 98
第一个问题是:"什么是into_iter?"
into_iter来自这个IntoIterator特质:
Run Code Online (Sandbox Code Playgroud)pub trait IntoIterator where <Self::IntoIter as Iterator>::Item == Self::Item, { type Item; type IntoIter: Iterator; fn into_iter(self) -> Self::IntoIter; }
当您想要指定如何将特定类型转换为迭代器时,可以实现此特征.最值得注意的是,如果一个类型实现IntoIterator它可以在for循环中使用.
例如,Vec实现IntoIterator......三次!
Run Code Online (Sandbox Code Playgroud)impl<T> IntoIterator for Vec<T> impl<'a, T> IntoIterator for &'a Vec<T> impl<'a, T> IntoIterator for &'a mut Vec<T>
每个变体略有不同.
这个消耗它Vec和它的迭代器产生值(T直接):
Run Code Online (Sandbox Code Playgroud)impl<T> IntoIterator for Vec<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(mut self) -> IntoIter<T> { /* ... */ } }
另外两个通过引用获取向量(不要被签名所欺骗,into_iter(self)因为self在两种情况下都是引用)并且它们的迭代器将生成对内部元素的引用Vec.
这个产生不可变引用:
Run Code Online (Sandbox Code Playgroud)impl<'a, T> IntoIterator for &'a Vec<T> { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; fn into_iter(self) -> slice::Iter<'a, T> { /* ... */ } }
虽然这个产生了可变引用:
Run Code Online (Sandbox Code Playgroud)impl<'a, T> IntoIterator for &'a mut Vec<T> { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; fn into_iter(self) -> slice::IterMut<'a, T> { /* ... */ } }
所以:
iter和之间有什么区别into_iter?
into_iter是获取迭代器的通用方法,无论此迭代器是否产生值,不可变引用或可变引用是否依赖于上下文,有时可能会令人惊讶.
iter并且iter_mut是临时方法.这适用于依赖于上下文的位,并且按照惯例,让您获得将产生引用的迭代器.
Rust by Example帖子的作者说明了来自依赖于into_iter被调用的上下文(即类型)的惊喜,并且还通过使用以下事实来复合问题:
IntoIterator没有实现[T; N],仅用于&[T; N]和&mut [T; N]这是非常令人惊讶的,into_iter因为所有类型(除了[T; N])都为所有3种变体(值和引用)实现它.数组不可能实现一个产生值的迭代器,因为它不能"缩小"以放弃它的项目.
至于为什么数组实现IntoIterator(以这种令人惊讶的方式):它可以在循环中迭代对它们的引用for.
joe*_*joe 14
我(一个Rust新手)从Google来到这里,寻求一个简单的答案,而其他答案没有提供。这是简单的答案:
iter() 通过引用遍历项目into_iter() 遍历项目,将其移至新范围iter_mut() 遍历项目,为每个项目提供可变的引用因此for x in my_vec { ... }本质上等同于my_vec.into_iter().for_each(|x| ... )-将这两个move元素都my_vec纳入...范围。
如果您只需要“查看”数据,请使用iter;如果您需要对其进行编辑/突变,请使用iter_mut;如果需要给它一个新的所有者,请使用into_iter。
这很有帮助:http : //hermanradtke.com/2015/06/22/effectively-using-iterators-in-rust.html
将其设置为社区Wiki,以便我犯任何错误时希望Rust专业人员可以编辑此答案。
我认为还有一点需要澄清。集合类型,例如Vec<T>and VecDeque<T>,有into_iter方法会产生,T因为它们实现了IntoIterator<Item=T>。没有什么可以阻止我们创建一个类型,Foo<T>如果它被迭代,它只会产生T另一种类型U。也就是说,Foo<T>实现IntoIterator<Item=U>.
实际上,在std: &Path implements IntoIterator<Item=&OsStr>和&UnixListener implements 中 有一些例子IntoIterator<Item=Result<UnixStream>>。
into_iter和iter回到原来的问题上的区别into_iter和iter。与其他人指出的类似,不同之处在于它into_iter是一个必需的方法,IntoIterator它可以产生IntoIterator::Item. 通常,如果一种类型的工具IntoIterator<Item=I>,按照惯例它具有也有两个特别的方法:iter和iter_mut其中产率&I和&mut I分别。
这意味着我们可以into_iter通过使用 trait bound创建一个接收具有方法的类型(即它是可迭代的)的函数:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我们不能*使用 trait 绑定来要求类型具有iter方法或iter_mut方法,因为它们只是约定。我们可以说它into_iter比iteror更广泛使用iter_mut。
iter和的替代品iter_mut另一个有趣的观察是这iter不是获得 yield 的迭代器的唯一方法&T。按照惯例(再次),集合类型SomeCollection<T>在std其中有iter方法也有其不可变的引用类型&SomeCollection<T>实现IntoIterator<Item=&T>。例如,&Vec<T> implements IntoIterator<Item=&T>,因此它使我们能够迭代&Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Run Code Online (Sandbox Code Playgroud)
如果在这两个工具中都v.iter()等价,那么为什么 Rust 提供两者?这是为了人体工程学。在循环中,它比;更简洁一些。但在其他情况下,比:&vIntoIterator<Item=&T>for&vv.iter()v.iter()(&v).into_iter()
let v = vec![1, 2];
let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();
Run Code Online (Sandbox Code Playgroud)
同样,在for循环中,v.iter_mut()可以替换为&mut v:
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
Run Code Online (Sandbox Code Playgroud)
into_iter和iter方法如果类型只有一种“方式”可以迭代,我们应该同时实现这两种方式。但是,如果有两种或更多的方式可以迭代,我们应该为每种方式提供一个特别的方法。
例如,String提供既不是into_iter也不iter是因为有两种方法可以迭代它:以字节为单位迭代其表示或以字符为单位迭代其表示。相反,它提供了两种方法:bytes用于迭代字节和chars用于迭代字符,作为iter方法的替代方法。
*好吧,从技术上讲,我们可以通过创建特征来做到这一点。但是我们需要为impl我们想要使用的每种类型使用该特征。同时,许多类型在std已经实现IntoIterator。
.into_iter()没有为数组本身实现,但只是&[].相比:
impl<'a, T> IntoIterator for &'a [T]
type Item = &'a T
Run Code Online (Sandbox Code Playgroud)
同
impl<T> IntoIterator for Vec<T>
type Item = T
Run Code Online (Sandbox Code Playgroud)
由于IntoIterator仅定义了&[T],因此切片本身的删除方式与Vec使用值时不同.(值无法移出)
现在,为什么这是一个不同的问题,我想学习自己.推测:数组本身就是数据,切片只是一个视图.在实践中,您不能将数组作为值移动到另一个函数中,只需传递它的视图,因此您也不能在那里使用它.
| 归档时间: |
|
| 查看次数: |
21353 次 |
| 最近记录: |