如何为简单的结构实现 Iterator 和 IntoIterator? [英] How to implement Iterator and IntoIterator for a simple struct?
问题描述
某人将如何为以下结构实现 Iterator
和 IntoIterator
特征?
How would someone implement the Iterator
and IntoIterator
traits for the following struct?
struct Pixel {
r: i8,
g: i8,
b: i8,
}
我尝试了以下各种形式,但都没有成功.
I've tried various forms of the following with no success.
impl IntoIterator for Pixel {
type Item = i8;
type IntoIter = Iterator<Item=Self::Item>;
fn into_iter(self) -> Self::IntoIter {
[&self.r, &self.b, &self.g].into_iter()
}
}
这段代码给了我一个编译错误
This code gives me a compile error
error[E0277]: the trait bound `std::iter::Iterator<Item=i8> + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:7:6
|
7 | impl IntoIterator for Pixel {
| ^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=i8> + 'static`
|
= note: `std::iter::Iterator<Item=i8> + 'static` does not have a constant size known at compile-time
= note: required by `std::iter::IntoIterator`
推荐答案
你的迭代器类型是 Iterator
,但是 Iterator
是一个 trait.特征由结构实现,它们本身并不存在.你也可以有一个引用 trait 对象(&Iterator
)、一个装箱的 trait 对象(Box
)或一个匿名的 trait 实现(impl Iterator
),所有这些都有一个已知的大小.
Your iterator type is Iterator<Item = Self::Item>
, but Iterator
is a trait. Traits are implemented by structs, they don't exist on their own. You could also have a reference trait object (&Iterator
), a boxed trait object (Box<Iterator>
) or an anonymous trait implementation (impl Iterator
), all of which have a known sizes.
相反,我们创建了一个PixelIntoIterator
,它具有已知的大小和实现 Iterator
本身:
Instead, we create a PixelIntoIterator
that has a known size and implements Iterator
itself:
struct Pixel {
r: i8,
g: i8,
b: i8,
}
impl IntoIterator for Pixel {
type Item = i8;
type IntoIter = PixelIntoIterator;
fn into_iter(self) -> Self::IntoIter {
PixelIntoIterator {
pixel: self,
index: 0,
}
}
}
pub struct PixelIntoIterator {
pixel: Pixel,
index: usize,
}
impl Iterator for PixelIntoIterator {
type Item = i8;
fn next(&mut self) -> Option<i8> {
let result = match self.index {
0 => self.pixel.r,
1 => self.pixel.g,
2 => self.pixel.b,
_ => return None,
};
self.index += 1;
Some(result)
}
}
fn main() {
let p = Pixel {
r: 54,
g: 23,
b: 74,
};
for component in p {
println!("{}", component);
}
}
这具有返回实际 i8
而非引用的好处.既然这些都这么小,你还是直接传吧.
This has the nice benefit of returning actual i8
s, not references. Since these are so small, you might as well pass them directly.
这会消耗 Pixel
.如果您有对 Pixel
的引用,您还需要实现一个不使用它的迭代器:
This consumes the Pixel
. If you had a reference to a Pixel
, you'd need to also implement an iterator that doesn't consume it:
impl<'a> IntoIterator for &'a Pixel {
type Item = i8;
type IntoIter = PixelIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
PixelIterator {
pixel: self,
index: 0,
}
}
}
pub struct PixelIterator<'a> {
pixel: &'a Pixel,
index: usize,
}
impl<'a> Iterator for PixelIterator<'a> {
type Item = i8;
fn next(&mut self) -> Option<i8> {
let result = match self.index {
0 => self.pixel.r,
1 => self.pixel.g,
2 => self.pixel.b,
_ => return None,
};
self.index += 1;
Some(result)
}
}
如果你想支持创建消费迭代器和非消费迭代器,你可以实现这两个版本.您始终可以引用您拥有的 Pixel
,因此您只需要 非消费变体.但是,拥有一个消费版本通常很好,这样您就可以返回迭代器而不必担心生命周期.
If you wanted to support creating both a consuming iterator and a non-consuming iterator, you can implement both versions. You can always take a reference to a Pixel
you own, so you only need the non-consuming variant. However, it's often nice to have a consuming version so that you can return the iterator without worrying about lifetimes.
通过重用已经存在的迭代器来编写它会更方便,例如,使用 [T;3]
it'd be much more convenient to write this by reusing iterators that already exists, e.g., with
[T; 3]
从 Rust 1.51 开始,您可以利用 array::IntoIter
:
As of Rust 1.51, you can leverage array::IntoIter
:
impl IntoIterator for Pixel {
type Item = i8;
type IntoIter = std::array::IntoIter<i8, 3>;
fn into_iter(self) -> Self::IntoIter {
std::array::IntoIter::new([self.r, self.b, self.g])
}
}
在以前的版本中,这可能有点傻,但是您可以通过将一些现有类型粘合在一起并使用 impl Iterator
来避免创建自己的迭代器类型:
In previous versions, it might be a bit silly, but you could avoid creating your own iterator type by gluing some existing types together and using impl Iterator
:
use std::iter;
impl Pixel {
fn values(&self) -> impl Iterator<Item = i8> {
let r = iter::once(self.r);
let b = iter::once(self.b);
let g = iter::once(self.g);
r.chain(b).chain(g)
}
}
这篇关于如何为简单的结构实现 Iterator 和 IntoIterator?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!