【问题标题】:How do I use concrete values with generic numeric types?如何将具体值与通用数字类型一起使用?
【发布时间】:2022-10-04 23:57:04
【问题描述】:

尝试编写在 f32 和 f64 上通用的结构/实现。

我使用 trait num_traits::float::Float 作为 trait bound。

但是当函数中使用具体值时会出现编译器错误,例如初始化数组或使用数组的长度(usize)时。 想将具体类型转换为泛型 T,还是什么? 我该如何处理?

示例 1:

pub struct RingArray<T: Float, const N: usize> {
    tail: usize,  // Index of the most recently added element
    data: [T; N], // Array containing the data.
}

impl<T: Float, const N: usize> RingArray<T, N> {
    /// Creates a new RingArray of with length `length` and initialized to `init_value`.
    pub fn new() -> Self {
        Self {
            tail: N - 1,           // raw index to the last element
            // Initialize the data array to 0.0
            data: [0.0; N],  //  <-- ERROR. Compiler complains here about 0.0.  Expected type T found {float}
        }
    
    }
}

示例 2:

pub struct MovingAverageFilter<T: Float, const N: usize> {
    ring_array: RingArray<T, N>,
    sum: T,
}
impl <T: Float, const N: usize> MovingAverageFilter<T, N> {
    pub fn push(&mut self, input: T) -> T {

        // Push the input and pop the head.
        let head = self.ring_array.push(input);

        // Add input to the sum and subtract the head
        self.sum = self.sum + input - head; 

        let length = self.ring_array.len();

        // Want to cast length to type T. How?
        self.sum/length  //  <-- ERROR. Expectded denom to be type T, found usize
    }
}

【问题讨论】:

    标签: generics rust


    【解决方案1】:

    0.0 是不能在通用上下文中使用的文字。相反,您可以使用来自num_traitsZero,这是具有有意义的“零”值的类型的特征:

    use num_traits::Zero;
    
    pub fn new() -> Self {
        Self {
            tail: N - 1, 
            // Initialize the data array to 0.0
            data: [Zero::zero(); N],
        }
    }
    

    对于第二部分,您尝试将通用数字类型除以 usize。您需要先将 usize 转换为 float 类型,您可以通过从同一个 crate 中通过 FromPrimitive 约束类型来做到这一点:

    use num_traits::FromPrimitive;
    
    impl <T: Float + FromPrimitive, const N: usize> MovingAverageFilter<T, N> {
        pub fn push(&mut self, input: T) -> T {
    
            // Push the input and pop the head.
            let head = self.ring_array.push(input);
    
            // Add input to the sum and subtract the head
            self.sum = self.sum + input - T::from_usize(head).unwrap(); 
    
            let length = self.ring_array.len();
    
            // Convert the usize to a T before dividing
            self.sum / T::from_usize(length).unwrap()
        }
    }
    

    【讨论】:

    • T::zero() 也可以在这里工作吗?如果是这样,是否有理由更喜欢Zero::zero()
    • 谢谢彼得!我也刚刚发现这个(非常相似的)解决方案似乎在这两种情况下都有效:``` T::from(any_value_goes_here).unwrap() ```
    猜你喜欢
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多