不安全的操作

作为本节的介绍,借用官方文档中的话,“应该尽量减少代码库中不安全代码的数量。” 考虑到这一点,让我们开始吧! Rust 中的不安全注解用于绕过编译器设置的保护; 具体来说,unsafe 主要用于以下四个方面

  • 解引用原始指针
  • 调用 unsafe 的函数或方法(包括通过 FFI 调用函数,请参阅本书前一章
  • 访问或修改静态可变变量
  • 实现不安全的 trait

原始指针

原始指针 * 和引用 &T 的功能类似,但引用始终是安全的,因为借用检查器保证它们指向有效数据。 对原始指针的解引用只能通过 unsafe 块完成。

fn main() {
    let raw_p: *const u32 = &10;

    unsafe {
        assert!(*raw_p == 10);
    }
}

调用不安全函数

某些函数可以声明为 unsafe,这意味着程序员有责任确保正确性,而不是编译器。 一个例子是 std::slice::from_raw_parts,它将根据指向第一个元素的指针和长度创建一个切片。

use std::slice;

fn main() {
    let some_vector = vec![1, 2, 3, 4];

    let pointer = some_vector.as_ptr();
    let length = some_vector.len();

    unsafe {
        let my_slice: &[u32] = slice::from_raw_parts(pointer, length);

        assert_eq!(some_vector.as_slice(), my_slice);
    }
}

对于 slice::from_raw_parts,必须遵守的假设之一是传入的指针指向有效的内存,并且指向的内存类型正确。 如果不遵守这些不变量,那么程序的行为将是未定义的,并且不知道会发生什么。