1. 调用外部函数(FFI)
- 场景阐述:当需要与其他语言(如C语言)编写的库进行交互时,Rust提供了
extern
关键字来声明外部函数。这些函数通常需要在 unsafe
块中调用,因为Rust无法对外部函数进行安全检查。
- 示例:
// 假设存在一个C函数定义在libexample.so中
// int add(int a, int b);
extern "C" {
fn add(a: i32, b: i32) -> i32;
}
fn main() {
unsafe {
let result = add(2, 3);
println!("The result of add is: {}", result);
}
}
2. 操作裸指针
- 场景阐述:裸指针(
*const T
和 *mut T
)绕过了Rust的内存安全检查机制。在某些性能敏感或者与底层硬件交互的场景中,可能需要使用裸指针,这时就需要 unsafe
块。
- 示例:
fn main() {
let mut num = 42;
let raw_ptr: *mut i32 = &mut num as *mut i32;
unsafe {
// 通过裸指针修改值
*raw_ptr = 43;
println!("The value is: {}", num);
}
}
3. 访问和修改未初始化内存
- 场景阐述:Rust通常要求变量在使用前必须初始化。但在一些特定的底层场景,比如实现内存分配器时,可能需要先分配未初始化的内存,然后再对其进行初始化,这个过程需要在
unsafe
块中完成。
- 示例:
use std::mem;
fn main() {
let mut uninit: mem::MaybeUninit<i32> = mem::MaybeUninit::uninit();
unsafe {
// 将值写入未初始化内存
uninit.as_mut_ptr().write(42);
let value = uninit.assume_init();
println!("The value is: {}", value);
}
}
4. 实现自定义Drop逻辑
- 场景阐述:虽然大多数情况下,Rust自动生成的
Drop
实现能满足需求,但在一些复杂场景,比如资源释放依赖特定顺序或者涉及外部资源时,手动实现 Drop
并在其中使用 unsafe
操作可能是必要的。
- 示例:
struct MyResource {
ptr: *mut u8,
}
impl Drop for MyResource {
fn drop(&mut self) {
unsafe {
std::ptr::drop_in_place(self.ptr);
std::alloc::dealloc(self.ptr, std::alloc::Layout::new::<u8>());
}
}
}