Trying to write structs/impls that are generic over f32 and f64.
I'm using trait num_traits::float::Float
as trait bounds.
But I get compiler errors when concrete values are used in the function, such as when an array is initialized or the length of the array (usize) is used. Wanting to cast concrete type to generic T, or something?? How do I handle this?
Thanks !
Example 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}
}
}
}
Example2:
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
}
}
CodePudding user response:
0.0
is a literal that can't be used in a generic context. Instead, you can use Zero
from num_traits
, which is a trait for types that have a meaningful "zero" value:
use num_traits::Zero;
pub fn new() -> Self {
Self {
tail: N - 1,
// Initialize the data array to 0.0
data: [Zero::zero(); N],
}
}
For the second part, you are trying to divide a generic numeric type by a usize
. You need to convert the usize
into the float type first, which you can do by constraining the type by FromPrimitive
from the same crate:
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()
}
}