gpt4 book ai didi

rust - 通过type_id检查不安全类型转换的安全性如何?

转载 作者:行者123 更新时间:2023-12-03 11:28:31 25 4
gpt4 key购买 nike

我有一个名为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)
}
}
}
如果使用 valuef64检查为 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());
}

最佳答案

一种更自然的实现所需方式的方法是为不同类型编写不同的实现:

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);
这没有提供全面的实现,但是很容易将其他类型添加到受支持的类型列表中。

关于rust - 通过type_id检查不安全类型转换的安全性如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64316469/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com