【问题标题】:Implementing mean function for generic types为泛型类型实现均值函数
【发布时间】:2023-03-08 15:20:02
【问题描述】:

我正在尝试编写一个函数来返回 Vector 的平均值。我希望它与泛型类型一起使用,但我在实现它时遇到了一些困难。

extern crate num; // 0.2.0

use num::Zero;
use std::ops::{Add, Div};

pub struct Vector<T> {
    pub size: usize,
    pub data: Vec<T>,
}

impl<T: Copy + Zero + Add<T, Output = T>> Vector<T> {
    pub fn sum(&self) -> T {
        self.data.iter().fold(T::zero(), |sum, &val| sum + val)
    }
}

impl<T: Copy + Zero + Add<T, Output = T> + Div<T, Output = T>> Vector<T> {
    pub fn mean(&self) -> T {
        let sum = self.sum();
        sum / self.data.len()
    }
}

Playground.

上面的例子不能编译,因为self.data.len()usizesumT 类型:

error[E0308]: mismatched types
  --> src/lib.rs:20:15
   |
20 |         sum / self.data.len()
   |               ^^^^^^^^^^^^^^^ expected type parameter, found usize
   |
   = note: expected type `T`
              found type `usize`

我知道我可以将签名更改为:

impl<T: Copy + Zero + Add<T, Output = T> + Div<usize, Output = T>> Vector<T>

它会编译——但这不是为 Rust 原始类型实现的。我该怎么办?

【问题讨论】:

    标签: generics rust


    【解决方案1】:

    基本类型实现the FromPrimitive trait,在the num crate 中定义,以允许基本类型之间的转换,包括usize。我们可以在函数上添加FromPrimitive绑定,然后我们可以将usize转换为T

    extern crate num; // 0.2.0
    
    use num::{FromPrimitive, Zero};
    use std::ops::{Add, Div};
    
    impl<T> Vector<T>
    where
        T: Copy + Zero + Add<T, Output = T> + Div<T, Output = T> + FromPrimitive,
    {
        pub fn mean(&self) -> T {
            let sum = self.sum();
            sum / FromPrimitive::from_usize(self.data.len()).unwrap()
        }
    }
    

    【讨论】:

      【解决方案2】:

      在许多情况下,计算输入类型的平均值是没有意义的。例如,整数 1 和 2 的整数平均值1。如果您希望能够获得任何可被视为i64 的值的迭代器的平均值并将平均值视为f64,您可以使用Iterator::sumInto

      fn avg_iter<I>(s: I) -> f64
      where
          I: IntoIterator,
          I::Item: Into<i64>,
      {
          let mut count = 0;
          let total = s
              .into_iter()
              .map(Into::into)
              .inspect(|_| count += 1)
              .sum::<i64>();
          total as f64 / count as f64
      }
      

      一些例子:

      use std::collections::VecDeque;
      
      fn main() {
          let a: Vec<u16> = vec![1, 2, 3];
          let b: Vec<u32> = vec![1, 2, 3];
          let c: VecDeque<u16> = vec![1u16, 2, 3].into();
      
          let v = avg_iter(a.iter().cloned());
          println!("{}", v);
          let v = avg_iter(a);
          println!("{}", v);
      
          let v = avg_iter(b.iter().cloned());
          println!("{}", v);
          let v = avg_iter(b);
          println!("{}", v);
      
          let v = avg_iter(c.iter().cloned());
          println!("{}", v);
          let v = avg_iter(c);
          println!("{}", v);
      }
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-18
        • 2021-06-27
        相关资源
        最近更新 更多