我有一个名为Magnitude的枚举:
pub enum Magnitude<T> {
/// A finite value
Finite(T),
/// Positive infinity
PosInfinite,
/// Negative infinity
NegInfinite,
}
并且我想要实现From
特性以能够从不同类型构造Magnitude:
impl<T: Any> From<T> for Magnitude<T> {
fn from(value: T) -> Self {
if value.type_id() == TypeId::of::<f64>() {
unsafe {
let value_f64 = (&value as *const T).cast::<f64>().as_ref().unwrap().clone();
if value_f64 == f64::INFINITY {
Magnitude::PosInfinite
} else if value_f64 == f64::NEG_INFINITY {
Magnitude::NegInfinite
} else {
Magnitude::Finite(value)
}
}
} else if value.type_id() == TypeId::of::<f32>() {
unsafe {
let value_f32 = (&value as *const T).cast::<f32>().as_ref().unwrap().clone();
if value_f32 == f32::INFINITY {
Magnitude::PosInfinite
} else if value_f32 == f32::NEG_INFINITY {
Magnitude::NegInfinite
} else {
Magnitude::Finite(value)
}
}
} else {
Magnitude::Finite(value)
}
}
}
如果使用value
检查f64
的类型为type_id
,将其转换为f64有多安全?
它通过了下面的测试,但我不知道它是否始终可以正常工作:
#[test]
fn f64_infinity() {
let pos_inf: Magnitude<f64> = f64::INFINITY.into();
let neg_inf: Magnitude<f64> = f64::NEG_INFINITY.into();
assert!(pos_inf.is_pos_infinite());
assert!(neg_inf.is_neg_infinite());
}
答案 0 :(得分:3)
一种更自然的实现所需方法的方法是针对不同类型编写不同的实现:
impl From<f32> for Magnitude<f32> {
fn from(value: f32) -> Self {
if value == f32::INFINITY {
Magnitude::PosInfinite
} else if value == f32::NEG_INFINITY {
Magnitude::NegInfinite
} else {
Magnitude::Finite(value)
}
}
}
但是,如果您已经有了具体的实现,则很难实现全面的实现
impl<T> From<T> for Magnitude<T> {
fn from(value: T) -> Self {
Magnitude::Finite(value)
}
}
产生
conflicting implementations of trait `std::convert::From<f32>` for type `Magnitude<f32>`:
--> src/lib.rs:22:1
|
10 | impl From<f32> for Magnitude<f32> {
| --------------------------------- first implementation here
...
22 | impl<T> From<T> for Magnitude<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Magnitude<f32>`
虽然有an accepted RFC to support specialization in Rust,但尚未完全实现。就目前而言,我建议使用一种不太通用的方法:
macro_rules! magnitude_from_float_impl {
($t:ty) => {
impl From<$t> for Magnitude<$t> {
fn from(value: $t) -> Self {
if value.is_infinite() {
if value.is_sign_positive() {
Magnitude::PosInfinite
} else {
Magnitude::NegInfinite
}
} else {
Magnitude::Finite(value)
}
}
}
}
}
macro_rules! magnitude_from_impl {
($t:ty) => {
impl From<$t> for Magnitude<$t> {
fn from(value: $t) -> Self {
Magnitude::Finite(value)
}
}
}
}
magnitude_from_float_impl!(f32);
magnitude_from_float_impl!(f64);
magnitude_from_impl!(i64);
magnitude_from_impl!(i32);
这没有提供全面的实现,但是很容易在支持的类型列表中添加其他类型。