如何为下面的结构实现Iterator和IntoIterator特征?
struct Pixel {
r: i8,
g: i8,
b: i8,
}我已经尝试了下面的各种形式,但都没有成功。
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`发布于 2015-05-14 00:47:34
您的迭代器类型是Iterator<Item = Self::Item>,但Iterator是一个特征。特征是由结构实现的,它们不是独立存在的。您还可以有一个引用特征对象(&Iterator)、一个盒装特征对象(Box<Iterator>)或一个匿名特征实现(impl Iterator),所有这些对象的大小都是已知的。
取而代之的是,我们创建一个已知大小并实现Iterator本身的PixelIntoIterator:
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,而不是引用。既然它们都很小,你不妨直接传递它们。
这将消耗Pixel。如果你有一个对Pixel的引用,你还需要实现一个不使用它的迭代器:
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,因此您只需要非使用的变体。然而,有一个消费版本通常是很好的,这样你就可以返回迭代器,而不用担心生命周期。
通过重用已经存在的迭代器(例如,使用[T; 3] )来编写
要方便得多
从Rust1.51开始,您可以利用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来避免创建自己的迭代器类型
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)
}
}发布于 2015-05-14 00:59:45
首先,IntoIter必须指向一个真正的struct,而不是一个trait,以便Rust能够传递该值(这就是Sized的意思)。对于数组,into_iter返回std::slice::Iter struct。
其次,典型的数组[1, 2, 3]不是在堆上分配的。事实上,允许编译器完全优化分配,转而指向预编译的数组。能够迭代数组而不将它们复制到任何地方,我认为这就是为什么数组的IntoIterator实现不像其他IntoIterator实现那样将数组移动到任何地方的原因。相反,它似乎引用了现有的数组。您可以从its signature中看到
impl<'a, T> IntoIterator for &'a [T; 3]
type Item = &'a T
type IntoIter = Iter<'a, T>
fn into_iter(self) -> Iter<'a, T>它接受对数组(&'a [T; 3])的引用。
因此,你不能以你想要的方式使用它。引用的数组必须比返回的迭代器存活时间长。Rust编译器告诉我们的Here's a version。
Vector有一个IntoIterator实现,可以真正地将数据移动到迭代器中,从而实现you can use it。
为了既快速又简单,返回一个数组而不是迭代器(playpen):
impl Pixel {
fn into_array(self) -> [i8; 3] {[self.r, self.g, self.b]}
}这样,数组首先移动到外部作用域中,然后可以从外部作用域的迭代器中引用它:
for color in &(Pixel {r: 1, g: 2, b: 3}).into_array() {
println! ("{}", color);
}https://stackoverflow.com/questions/30218886
复制相似问题