unsafe 基础
学习目标
- 理解 unsafe 的作用和边界
- 掌握 unsafe 可以做的四件事
- 理解安全抽象
核心概念
unsafe 不是"关闭安全检查"
// unsafe 块允许你做编译器无法验证安全性的操作
// 但借用检查等仍然生效
unsafe {
// 你可以:
// 1. 解引用裸指针
// 2. 调用 unsafe 函数
// 3. 访问/修改可变静态变量
// 4. 实现 unsafe trait
}
裸指针
fn main() {
let mut num = 5;
// 创建裸指针(安全)
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
// 解引用裸指针(必须在 unsafe 中)
unsafe {
println!("r1 = {}", *r1);
*r2 = 10;
println!("r2 = {}", *r2);
}
}
unsafe 函数
unsafe fn dangerous() {
println!("危险操作");
}
fn safe_wrapper() {
// 在安全函数中封装 unsafe 操作
unsafe {
dangerous();
}
}
安全抽象
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = slice.len();
let ptr = slice.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
fn main() {
let mut data = vec![1, 2, 3, 4, 5];
let (left, right) = split_at_mut(&mut data, 3);
println!("left: {:?}, right: {:?}", left, right);
}
可变静态变量
static mut COUNTER: u32 = 0;
fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn main() {
add_to_count(3);
unsafe {
println!("COUNTER: {}", COUNTER);
}
}
实践练习
练习 1:安全的 swap
fn my_swap<T>(a: &mut T, b: &mut T) {
unsafe {
let temp = std::ptr::read(a);
std::ptr::copy_nonoverlapping(b, a, 1);
std::ptr::write(b, temp);
}
}
fn main() {
let mut x = 5;
let mut y = 10;
my_swap(&mut x, &mut y);
println!("x={}, y={}", x, y);
}
小结
| unsafe 能做 | 说明 |
|---|---|
| 解引用裸指针 | *const T, *mut T |
| 调用 unsafe 函数 | 标记为 unsafe 的函数 |
| 访问可变静态变量 | static mut |
| 实现 unsafe trait | unsafe trait |
原则:最小化 unsafe 范围,用安全抽象封装。