Rust 当通过类型_id进行检查时,不安全强制转换的安全性如何?

Rust 当通过类型_id进行检查时,不安全强制转换的安全性如何?,rust,unsafe,Rust,Unsafe,我有一个叫做震级的枚举: pub枚举大小{ ///有限值 有限(T), ///正无穷大 无限, ///负无穷大 负无限, } 我想从trait中实现,以便能够从不同类型中构造幅值: impl From<f32> for Magnitude<f32> { fn from(value: f32) -> Self { if value == f32::INFINITY { Magnitude::PosInfinite

我有一个叫做震级的枚举:

pub枚举大小{
///有限值
有限(T),
///正无穷大
无限,
///负无穷大
负无限,
}
我想从trait中实现
,以便能够从不同类型中构造幅值:

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 From用于震级{
fn from(值:T)->Self{
如果value.type_id()==TypeId::of::(){
不安全{
让value_f64=(&value as*const T).cast::().as_ref().unwrap().clone();
如果值_f64==f64::无穷大{
震级:无限
}如果值为负无穷大,则为else{
震级:负无穷大
}否则{
幅值::有限(值)
}
}
}else if value.type_id()==TypeId::of::(){
不安全{
让value_f32=(&value as*const T).cast::().as_ref().unwrap().clone();
如果值_f32==f32::无穷大{
震级:无限
}如果值_f32==f32::NEG_无穷大,则为else{
震级:负无穷大
}否则{
幅值::有限(值)
}
}
}否则{
幅值::有限(值)
}
}
}
如果使用
type\u id
value
检查为类型为
f64
,将其强制转换为f64有多不安全

它通过了下面的测试,但我不知道它是否会一直正常工作:

#[测试]
fn f64_无穷大(){
让pos_inf:magnity=f64::INFINITY.into();
设neg_inf:magnity=f64::neg_INFINITY.into();
断言!(pos_inf.is_pos_infinite());
断言!(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 From用于震级{
fn from(值:f32)->Self{
如果值==f32::无穷大{
震级:无限
}如果值==f32::NEG_无穷大,则为else{
震级:负无穷大
}否则{
幅值::有限(值)
}
}
}
然而,如果您已经有了具体的实现,那么很难实现一揽子实现

impl<T> From<T> for Magnitude<T> {
    fn from(value: T) -> Self {
        Magnitude::Finite(value)
    }
}
impl From用于震级{
fn from(值:T)->Self{
幅值::有限(值)
}
}
导致

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>`
trait`std::convert::From`for type`magnize`的冲突实现: -->src/lib.rs:22:1 | 10 | impl From表示震级{ |-------------------------------------这里的第一个实现 ... 22 |因震级而从impl开始{ |^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^的冲突实现`
虽然有,但这尚未得到充分实施。目前,我建议采取一种稍微不那么笼统的做法:

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);
macro\u规则!来自\u float\u impl的大小\u{
($t:ty)=>{
因震级而引起的impl{
fn from(值:$t)->Self{
如果值为_无穷大(){
如果值为正(){
震级:无限
}否则{
震级:负无穷大
}
}否则{
幅值::有限(值)
}
}
}
}
}
宏\u规则!来自\u impl的大小\u{
($t:ty)=>{
因震级而引起的impl{
fn from(值:$t)->Self{
幅值::有限(值)
}
}
}
}
来自浮点运算的幅值(f32);
来自浮点运算的幅值(f64);
震级(i64);
震级(i32);

这并没有提供全面的实现,但很容易将更多类型添加到支持的类型列表中。

这并不能回答您的问题,但您不能使用
Any
中的
downcast_ref
方法吗?它似乎更合适,并且不需要
safe
@nikrasmohrin the
downcast_ref()
downcast_mut()
方法用于在运行时进行动态向下转换。它们只针对类型为
dyn Any+'static
和类似的trait对象实现,但不针对实现
Any
trait的具体类型。@Nikrasmohrin如果我没有弄错的话,
downcast\u ref
是针对
dyn Any
实现的,这意味着我必须实现
From
而不是
From
。但是
From
受到
size
特性的限制,而
dyn-Any
没有实现这一特性,因为它的大小在编译时是未知的。对,这是正确的!回到你的问题:我查看了
downcast\u-ref
的源代码,它们在那里投射了指针在比较了类型ID之后().你应该good@NiklasMohrin这看起来很有希望!我想知道这个
如果type_check then cast
是正确的,rust可以在kotlin中有类似智能cast的东西……这是一个很好的解决方案,但它比一块不安全的cast更加复杂和沉重。当然,如果我提到的类型的cast是安全的,那么这一切都是正确的。如果不是的话afe,你的解决方案就是要走的路。这就是为什么我好奇和担心的原因!关于提到的cast的安全性,你的cast很好–它只是比它需要的更复杂。
let value_f64=*(&value as*const T as*const f64)
在我看来更简洁易读。谢谢@SvenMarnach的帮助:)。是的,你的可读性更强!我会用它来代替