Привидение типов и арифметические операции в универсальных функциях
Решил написать нечто универсальной функции range, которая заполняла бы вектор любим примитивным типом - i32, u32, f32 и тд - и возвращала бы его. Проблема состоит в приведении типов и арифметическими операциями над ними. Как универсальный тип Т приводить к конкретным типам и обратно, чтобы можно было сравнивать тип Т с другими типами и проводить над ними арифметические операции?
use std::ops::Add;
fn rngg<T>(start: T, stop: T, step: T) -> Vec<T>
where T: Add<Output=T> + Copy + PartialOrd {
let mut v: Vec<T> = Vec::new();
if step == 0 {
let mut tmp = 0;
while tmp < step {
v.push(tmp);
tmp = tmp + (1 as T);
}
}
else {
let mut tmp = start + step;
while tmp < stop {
v.push(tmp);
tmp = tmp + step;
}
}
v
}
fn main() {
let r = rngg(1.0, 18.0, 2.0);
for i in &r {
println!("{:?}", i);
}
Ответы (1 шт):
Здесь проблема в том, что целочисленные литералы получают определенный тип (i32) и не совместимы с обобщенным типом T. Их можно преобразовать к типу T, потребовав, чтобы для этого типа существовали преобразования Into или TryInto:
use std::convert::TryInto;
use std::fmt::Debug;
use std::ops::Add;
fn rngg<T>(start: T, stop: T, step: T) -> Vec<T>
where
T: Add + Copy + PartialOrd,
i8: TryInto<T>,
<i8 as TryInto<T>>::Error: Debug,
{
let zero = 0i8.try_into().unwrap();
let one = 1i8.try_into().unwrap();
let mut v: Vec<T> = Vec::new();
if step == zero {
let mut tmp = zero;
while tmp < step {
v.push(tmp);
tmp = tmp + one;
}
}
else {
let mut tmp = start + step;
while tmp < stop {
v.push(tmp);
tmp = tmp + step;
}
}
v
}
С Into код попроще, но набор подходящих типов чуть-чуть сужается из-за того, что безошибочное преобразование из i8 в u8 невозможно в общем случае и соответствующим образом параметризированный From не определен.
Если хочется совсем обобщенного подхода, можно воспользоваться, например, библиотекой num или определить свой типаж для примитивных типов:
trait FieldIdentities {
const ZERO: Self;
const ONE: Self;
}
impl FieldIdentities for i32 {
const ZERO: i32 = 0;
const ONE: i32 = 1;
}