Вы можете думать о признаке со связанным типом как о функции времени компиляции, которая отображается между типами.Например:
trait MapType {
type Output;
}
impl MapType for f64 {
type Output i64;
}
impl MapType for bool {
type Output u8;
}
Для каждого типа, который вам может понадобиться, вы можете реализовать MapType
для обеспечения сопоставления с уникальным типом Output
.
В вашем случае речь идет о парахтипов, и вы можете расширить идею выше, добавив параметр:
trait Normalize<T>: Sized {
type Norm;
}
Каждая реализация Normalize
создает уникальный тип Norm
для комбинации двух типов, Self
и T
.
Но вам также понадобятся некоторые ограничения;в конце концов, вам нужно будет иметь возможность фактически конвертировать между этими типами.И если число слишком велико для преобразования, преобразование завершится неудачей, поэтому вам понадобятся дополнительные ограничения типов TryFrom
и TryInto
, чтобы указать, какие вещи можно преобразовать во что:
use std::convert::{TryFrom, TryInto};
trait Normalize<T>: Sized
where
T: TryInto<Self::Norm>,
{
type Norm: TryFrom<Self>;
}
Реализуйте его для пар типов, которые вы хотите:
impl Normalize<u32> for f64 {
type Norm = f64;
}
impl Normalize<f64> for u32 {
type Norm = f64;
}
А также для всех пар того же типа :
impl<X> Normalize<X> for X {
type Norm = X;
}
Затем можно реализоватьnormalize
вот так:
fn normalize<A, B>(arg1: Option<A>, arg2: Option<B>) -> (Option<A::Norm>, Option<A::Norm>)
where
A: Normalize<B>,
A::Norm: TryFrom<B>,
{
(
arg1.and_then(|a| a.try_into().ok()),
arg2.and_then(|b| b.try_into().ok())
)
}
fn main() {
println!("{:?}", normalize(Some(1u32), Some(1u32))); // (Some(1), Some(1))
println!("{:?}", normalize(Some(1f64), Some(1u32))); // (Some(1.0), Some(1.0))
println!("{:?}", normalize(Some(1u32), Some(1f64))); // (Some(1.0), Some(1.0))
println!("{:?}", normalize(Some(1f64), Some(1f64))); // (Some(1.0), Some(1.0))
}
Вы быстро поймете, что я немного обманул здесь, используя u32
вместо u64
.Это потому, что нет реализации TryFrom<u64>
для f64
.Если вам нужны эти пары типов, вы все равно можете придерживаться того же подхода, который я описал, но вам нужно будет определить собственную версию черт TryInto
и TryFrom
и реализовать их самостоятельно для всех пар типов, которые вы используете.необходимо.