Rust 的主要缺点是其对行为的强大的静态担保。但安全检查是保守的:有些程序实际上是安全的,但是编译器无法证实这是真的。为了写这种程序,我们需要告诉编译器放宽限制。为此, Rust 有一个关键词,unsafe。代码使用 unsafe 比正常的代码有更少的限制。
让我们复习语法,然后我们将讨论语义。unsafe 在两种情况下被使用。第一个情况是标记一个函数为不安全:
unsafe fn danger_will_robinson() {
// scary stuff
}
例如,所有函数调用 FFI 时必须标记为 unsafe。第二个使用 unsafe 情况是不安全块:
unsafe {
// scary stuff
}
能够明确划定可能有漏洞的代码是非常重要的,并且这些漏洞能造成大问题。如果 Rust 程序段错误,你能确定这部分中哪里标记为 unsafe。
在 Rust 的上下文中,safe 的意思是“不做任何不安全的事。” 这很简单!
好吧,让我们再试一次:什么是不安全的?这里有一个列表:
这是很多东西。注意到各种各样的不好的但没有标记为 unsafe 的行为是很重要的。
Rust 不能防止各种各样的软件问题。bug 代码可以并将写在 Rust。这些行为并不好,但他们不符合 unsafe。
在不安全的函数和不安全的代码块内,Rust 通常会让你做三件通常不会做的事。以下就是这三件事:
就这样。重要的是,例如, unsafe 不会“关掉借用查器”。将 unsafe 添加到一些随机 Rust 代码并没有改变其语义,它不会开始接受任何东西。
但是它会让你写一些打破一些规则的东西。让我们学习这三种能力。
Rust 有一个称为‘static mut’的特性,它允许可变的全局状态。这样做会导致数据竞赛,因此本身是不安全的。有关详细信息,请参本书的静态部分。
原始指针让你做任意指针的运算,会导致许多不同的内存安全问题。在某种意义上,一个任意指针的解除引用的能力是你可以做的最危险的事情。更多关于原始指针,请看本书相关部分。
这最后的能力关于 unsafe 的两个方面:您只能调用一个 unsafe 块内标记 unsafe 的函数。
这种能力是强大的。Rust 为 unsafe 函数提供一些编译器特性,绕过安全检查和一些安全功能,换来安全速度。
我将再次重复:即使你可以在 unsafe 块和函数中做任意事情,并不意味着你应该这样做。虽然你坚持不变量编译器仍然将起作用,所以要小心!