如何为以下结构实现 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`
2 回答
你的迭代器类型是
Iterator<Item = Self::Item>
,但Iterator
是一个特征 . 特征是由结构体实现的,它们本身并不存在 . 您还可以拥有一个参考特征对象(&Iterator
),一个盒装特征对象(Box<Iterator>
)或一个匿名特征实现(impl Iterator
,所有这些都具有已知的大小 .相反,我们创建一个具有已知大小的
PixelIntoIterator
并实现Iterator
本身:这有很好的好处,返回实际的
i8
,而不是引用 . 由于它们很小,你可以直接传递它们 .这会消耗
Pixel
. 如果你有一个Pixel
的引用,你'd need to also implement an iterator that doesn' t消耗它:如果您想支持创建消费迭代器和非消耗迭代器,则可以实现这两个版本 . 您始终可以引用您拥有的
Pixel
,因此您只需要非消费变量 . 但是,拥有一个消费版本通常很好,这样你就可以返回迭代器而不必担心生命周期 .它可能有点傻,但您可以通过将一些现有类型粘合在一起并使用impl trait来避免创建自己的迭代器类型:
首先,
IntoIter
必须指向一个真正的struct
而不是指向trait
,以便Rust能够传递该值(这就是Sized
的含义) . 如果数组into_iter
返回std::slice::Iterstruct
.其次,典型的数组
[1, 2, 3]
未在堆上分配 . 实际上,允许编译器完全优化掉分配,而是指向预编译的数组 . 能够迭代数组而不将它们复制到任何地方我认为数组的IntoIterator
实现不会像其他IntoIterator
实现那样将数组移动到任何地方 . 相反,它似乎引用了现有的数组 . 你可以从its signature看到它需要一个数组的引用(
&'a [T; 3]
) .因此,你可以尝试.2859910 . 引用的数组必须比返回的迭代器更长 . Here's a version Rust编译器这么说 .
Vector有一个
IntoIterator
实现,它真正将数据移动到迭代器中,因此you can use it .附:为了使它既快又简单,返回一个数组而不是一个迭代器(playpen):
这样,数组首先移动到外部作用域,然后可以从外部作用域的迭代器中引用它: