可以在安全的Rust中进行转换会导致运行时错误吗?

时间:2015-09-29 21:53:29

标签: casting rust

我正在摆弄Any,并且只是为了更深入地了解Rust。从C#我习惯了这样一个事实,即转换会导致运行时异常,因为在C#中进行转换基本上意味着亲爱的编译器,相信我,我知道我在做什么请把它转换成int32因为我知道它会起作用。

但是,如果你正在进行无效的强制转换,那么程序将在运行时出现异常。所以我想知道(安全)Rust中的转换是否同样会导致运行时异常。

所以,我想出了这个代码来试试。

use std::any::Any;

fn main() {
    let some_int = 4;
    let some_str = "foo";
    {
      let mut v = Vec::<&Any>::new();
      v.push(&some_int);
      v.push(&some_str);

      // this gives a None
      let x = v[0].downcast_ref::<String>();
      println!("foo {:?}", x);

      //this gives Some(4)
      let y = v[0].downcast_ref::<i32>();
      println!("foo {:?}", y);

      //the compiler doesn't let me do this cast (which would lead to a runtime error)
      //let z = v[1] as i32;

    }
}

到目前为止,我的观察结果是编译器似乎阻止了我的这种运行时异常,因为我必须强制转换downcast_ref,它返回一个Option,这使得它再次安全。当然,我可以unwrap None将其炸毁,但这不是我的观点;)

编译器阻止我编写可能导致运行时错误的let z = v[1] as i32;。那么,假设在安全的Rust中进行转换永远不会导致运行时错误,这是正确的吗?

我知道防止运行时错误正是Rust的全部意义所以它非常有意义,我只想验证我的观察结果:)

2 个答案:

答案 0 :(得分:5)

在Rust中使用as进行投射非常有限。它只允许在原始数字和字符类型之间,指针和引用之间进行转换,以及根据具体类型的值创建特征对象,例如,所有 - as都不可重载。因此,使用as进行转换始终是无恐慌的,但如果您正在转换无法在目标类型中表示的值,则可以观察到数值溢出,这可能是也可能不是。

在Rust中,没有来自C#或Java的强制转换操作符。最接近它的是std::mem::transmute(),它与C ++中的reinterpret_cast非常相似。然而,它是unsafe,即使它有其局限性 - 它只能转换具有相同大小的类型的值。

答案 1 :(得分:3)

那么,这取决于你如何定义&#34;运行时错误&#34;和&#34;结果为&#34;。

正如弗拉基米尔所说,as仅适用于原始转换,但却无法实现。但目前(Rust 1.3)有一个邪恶的小洞:casting floating point values to an integer

如果你试图转换一个没有相应整数值的浮点值,结果就是你得到一个包含&#34;&#34;的整数。一个奇怪的东西&#34; LLVM假设不存在(因为当然你在检查之前检查了转换是否有意义)。编译器会根据可能发生的事情进行优化。

最终结果是,您可以通过使用非常大的值来创建奇怪的未定义整数,从而在运行时产生不一致的结果,从而导致崩溃或损坏内存,可能包括受控和不受控制的崩溃。

我的意思是,它不会假设这样做,并且解决方案可能将涉及使as恐慌,因为当有人要求编译器评估f32::NAN as i32

时,你会做什么