我正在摆弄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的全部意义所以它非常有意义,我只想验证我的观察结果:)
答案 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
?