如何为简单的结构实现Iterator和IntoIterator? [英] How to implement Iterator and IntoIterator for a simple struct?

查看:147
本文介绍了如何为简单的结构实现Iterator和IntoIterator?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何为以下结构实现 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 i8s, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆