在 Rust 中使用迭代器组合实现“IntoIterator”时如何找到关联类型“IntoIter”?

How to find the associated type `IntoIter` when implementing `IntoIterator` by using iterator composition in Rust?

我目前正在尝试实现一个数组结构。我想以一种动态生成基本结构的方式为 SOA 实现 IntoIterator,就好像我在结构数组上进行迭代一样。这是类型:结构及其 SOA,

struct Particle {
    x: f64,
    y: f64,
    v: [f64; 3]
}

struct ParticleSOA {
    x: Vec<f64>,
    y: Vec<f64>,
    v: Vec<[f64; 3]>,
}

通过使用 itertools 中的 'izip!' 宏,通过压缩我的 SOA 的 Vec 并将生成的元组映射到原始结构来构建迭代器非常容易.但是,我无法找到 IntoIterator 特征所需的关联类型 IntoIter 的类型。

impl IntoIterator for ParticleSOA{
    type Item = Particle;

    type IntoIter = ???;

    fn into_iter(self) -> Self::IntoIter {
       izip!(self.x,self.y,self.v).map(Particle::from)
    }
}

有没有一种聪明的方法可以从我对 into_iter 函数的实现中推断类型,或者我唯一的选择是手动计算出由迭代器函数组合创建的精确类型?

编辑

秘诀就是摆脱闭包,尤其是隐藏在 izip 中的闭包! Itertools 具有生成可用类型的 multizip 函数。

impl IntoIterator for ParticleSOA {
    type Item = Particle;

    fn into_iter(self) -> Self::IntoIter {
        multizip((self.x, self.y, self.v)).map(Particle::from)
    }

    type IntoIter = Map<
        itertools::Zip<(
            std::vec::IntoIter<f64>,
            std::vec::IntoIter<f64>,
            std::vec::IntoIter<[f64; 3]>,
        )>,
        fn((f64, f64, [f64; 3])) -> Particle,
    >;
}

注意:我的结构方便地实现了 From<(f64, f64, [f64; 3])>.

您可以 return 一个盒装迭代器,因此如果您的实现发生变化,return 类型不需要:

use itertools::izip; // 0.10.3

struct Particle {
    x: f64,
    y: f64,
    v: [f64; 3]
}

struct ParticleSOA {
    x: Vec<f64>,
    y: Vec<f64>,
    v: Vec<[f64; 3]>,
}

impl IntoIterator for ParticleSOA{
    type Item = Particle;

    type IntoIter = Box<dyn Iterator<Item=Self::Item>>;

    fn into_iter(self) -> Self::IntoIter {
       Box::new(izip!(self.x,self.y,self.v).map(|(x, y, v)| Particle {x, y , v}))
    }
}

Playground

否则类型应该是近似值:

Map<Zip<(f64, f64, [f64; 3])>, Fn>

比较复杂的类型。

你也可以创建自己的函数,而不是实现特征:

impl ParticleSOA {
    #[inline]
    fn into_iter(self) -> impl Iterator<Item=Particle> {
        izip!(self.x, self.y, self.v).map(|(x, y, v)| Particle { x, y, v })
    }
}

Playground

加上@Netwave 所说的内容,使用不稳定的特性 type_alias_impl_trait 您可以在关联类型中指定 impl Iterator

#![feature(type_alias_impl_trait)]

impl IntoIterator for ParticleSOA {
    type Item = Particle;

    type IntoIter = impl Iterator<Item = Particle>;

    fn into_iter(self) -> Self::IntoIter {
       izip!(self.x,self.y,self.v).map(Particle::from)
    }
}

Playground.