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 thedowncast_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的帮助:)。是的,你的可读性更强!我会用它来代替