如何为简单的结构实现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()
}
}
此代码给出了编译错误
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< Item = Self :: Item>
,但是 Iterator
是一个特质。特征是由结构实现,它们本身不存在。你也可以有一个参考特征对象(& Iterator
)或盒装特征对象( Box< 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
) or boxed trait object (Box<Iterator>
), both of which have a known sizes.
相反,我们创建一个 PixelIntoIterator
,它具有已知的大小和 implements 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 }
}
}
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);
}
}
返回实际的<$ c有很好的好处$ c> i8 s,不是参考。由于它们非常小,你可以直接传递它们。
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 }
}
}
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.
这篇关于如何为简单的结构实现Iterator和IntoIterator?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!