简体   繁体   English

是否可以在 Rust 中实现自定义 Iterator::sum?

[英]Is it possible to implement a custom Iterator::sum in Rust?

I am trying to learn about iterators with an iterator that produces triangle numbers.我正在尝试使用生成三角形数的迭代器来了解迭代器。 Triangle numbers are 1, 3, 6, 10, 15 where 1 = 1, 3 = 1 + 2, 6 = 1 + 2 + 3 etc. I have the basics of this created:三角形数是 1, 3, 6, 10, 15 其中 1 = 1, 3 = 1 + 2, 6 = 1 + 2 + 3 等等。我创建了以下基础知识:

pub struct Triangle {
    cur: u32,
    n: u32,
    m: u32,
}

impl Iterator for Triangle {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        if self.n == self.m {
            return None;
        }
        self.n = self.n + 1;
        self.cur = self.cur + self.n;

        Some(self.cur)
    }
}

A quick runnable example of this is一个快速运行的例子是

let t = Triangle { cur: 0, n: 0, m: 10 };
let s: u32 = t.sum();
println!("{}", s);  // prints 220

Is it possible to create a custom summation function for the iterator that returns type u32 ?是否可以为返回类型u32的迭代器创建自定义求和函数? I was hoping to be able to do this with the default iterator and sum functions, and not have to make my own specialized function.我希望能够使用默认的迭代器和 sum 函数来做到这一点,而不必制作我自己的专用函数。

What I was hoping to be able to do is:我希望能够做的是:

use std::iter::Sum;

impl Sum<u32> for u32 {
    fn sum<I>(iter: I) -> Self
    where
        I: Triangle,
    {
        let nsum = (self.n * (self.n + 1) * (self.n + 2)) / 6;
        let msum = (self.m * (self.m + 1) * (self.m + 2)) / 6;
        msum - nsum
    }
}

but this does not work.但这不起作用。 The error that I get with this is我得到的错误是

error[E0404]: expected trait, found struct `Triangle`
  --> src/main.rs:26:12
   |
26 |         I: Triangle,
   |            ^^^^^^^^ not a trait

I could change it from Triangle to Iterator like it wants, but that would prevent me from accessing the m and n values of the Triangle struct.我可以根据需要将它从Triangle更改为Iterator ,但这会阻止我访问Triangle结构的mn值。

How do I do this?我该怎么做呢? Is it impossible?不可能吗? I know that I could write my own function like my_sum() , but I was hoping to be able to do it in the context of an iterator.我知道我可以编写自己的函数,比如my_sum() ,但我希望能够在迭代器的上下文中做到这一点。

You cannot specialize the existing implementation of Sum , but you can specialize Iterator::sum in your iterator!你不能特化现有的Sum实现,但你可以特化Iterator::sum在你的迭代器中! It's a bit tricky, though, since its return type is generic.不过,这有点棘手,因为它的返回类型是通用的。

use std::iter::{self, Sum};

impl Iterator for Triangle {
    // existing members are unchanged

    fn sum<S>(self) -> S
    where
        S: Sum<Self::Item>,
    {
        let nsum = (self.n * (self.n + 1) * (self.n + 2)) / 6;
        let msum = (self.m * (self.m + 1) * (self.m + 2)) / 6;
        S::sum(iter::once(msum - nsum))
    }
}

We cannot return a fixed type (such as u32 ), as that would not respect the contract defined by the Iterator trait.我们不能返回固定类型(例如u32 ),因为这不符合Iterator trait 定义的契约。 All we know about the return type S is that it implements Sum<Self::Item> .我们只知道返回类型S实现了Sum<Self::Item> Sum has a single method, sum , that returns Self , so we can use it to produce a value of type S . Sum有一个返回Self方法sum ,因此我们可以使用它来生成S类型的值。 The method expects an iterator;该方法需要一个迭代器; we feed it a Once , "an iterator that yields an element exactly once".我们给它一个Once ,“一个只产生一次元素的迭代器”。 Since that iterator will iterate a fixed number of times, we can expect sum to perform a fixed number of operations.由于该迭代器将迭代固定次数,我们可以预期sum执行固定次数的操作。

When you compile the program in release mode and S is u32 , the whole sum call is optimized away, and the function returns msum - nsum directly.当你在发布模式下编译程序并且Su32 ,整个sum调用被优化掉,函数直接返回msum - nsum

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM