使用“均值”方法扩展迭代器

时间:2017-05-11 16:51:09

标签: rust

我正在尝试为Iterator实现mean方法,就像使用sum一样。 但是,sumIterator方法,因此我决定为实现Iterator的任何类型实现特征:

pub trait Mean<A = Self>: Sized {
    fn mean<I: Iterator<Item = A>>(iter: I) -> f64;
}

impl Mean for u64 {
    fn mean<I: Iterator<Item = u64>>(iter: I) -> f64 {
        //use zip to start enumeration from 1, not 0
        iter.zip((1..))
            .fold(0., |s, (e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
    }
}

impl<'a> Mean<&'a u64> for u64 {
    fn mean<I: Iterator<Item = &'a u64>>(iter: I) -> f64 {
        iter.zip((1..))
            .fold(0., |s, (&e, i)| (e as f64 + s * (i - 1) as f64) / i as f64)
    }
}

trait MeanIterator: Iterator {
    fn mean(self) -> f64;
}

impl<T: Iterator> MeanIterator for T {
    fn mean(self) -> f64 {
        Mean::mean(self)
    }
}

fn main() {
    assert_eq!([1, 2, 3, 4, 5].iter().mean(), 3.);
}

Playground

错误:

error[E0282]: type annotations needed
  --> src/main.rs:26:9
   |
26 |         Mean::mean(self)
   |         ^^^^^^^^^^ cannot infer type for `Self`

有没有办法修复代码,或者在Rust中是不可能的?

2 个答案:

答案 0 :(得分:5)

  

就像使用sum

一样

让我们来看看sum的工作原理:

fn sum<S>(self) -> S
    where Self: Sized,
          S: Sum<Self::Item>,

sum在任何迭代器上实现,只要结果类型S为迭代值实现Sum即可。 调用者可以选择结果类型。 Sum定义为:

pub trait Sum<A = Self> {
    fn sum<I>(iter: I) -> Self 
        where I: Iterator<Item = A>;
}

Sum::sum采用A的迭代器,并生成一个从中实现的类型的值。

我们只需复制粘贴结构,更改Sum Mean并简单实现:

trait MeanExt: Iterator {
    fn mean<M>(self) -> M
        where M: Mean<Self::Item>,
              Self: Sized,
    {
        M::mean(self)        
    }
}

impl<I: Iterator> MeanExt for I {}

trait Mean<A = Self> {
    fn mean<I>(iter: I) -> Self 
        where I: Iterator<Item = A>;
}

impl Mean for f64 {
    fn mean<I>(iter: I) -> Self
        where I: Iterator<Item = f64>
    {
        let mut sum = 0.0;
        let mut count: usize = 0;

        for v in iter {
            sum += v;
            count += 1;
        }

        if count > 0 {
            sum / (count as f64)
        } else {
            0.0
        }
    }
}

impl<'a> Mean<&'a f64> for f64 {
    fn mean<I>(iter: I) -> Self
        where I: Iterator<Item = &'a f64>
    {
        iter.cloned().mean()
    }
}

fn main() {
    let mean: f64 = [1.0, 2.0, 3.0].iter().mean();
    println!("{:?}", mean);
    let mean: f64 = vec![-1.0, 2.0, 1.0].into_iter().mean();
    println!("{:?}", mean);
}

答案 1 :(得分:2)

你可以这样做,例如:

pub trait Mean {
    fn mean(self) -> f64;
}

impl<F, T> Mean for T
    where T: Iterator<Item = F>,
          F: std::borrow::Borrow<f64>
{
    fn mean(self) -> f64 {
        self.zip((1..))
            .fold(0.,
                  |s, (e, i)| (*e.borrow() + s * (i - 1) as f64) / i as f64)
    }
}

fn main() {
    assert_eq!([1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
    assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].iter().mean(), 3.);
    assert_eq!(vec![1f64, 2f64, 3f64, 4f64, 5f64].into_iter().mean(), 3.);
}

我使用Borrow特征来支持f64&f64上的迭代器。