与不安全 Rust 交互
了解何时以及如何使用 `unsafe` 代码块绕过 Rust 的安全检查,从而实现 FFI 和底层内存操作。
与不安全 Rust 交互 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 3 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。
不安全 Rust:简介
欢迎学习不安全 Rust!Rust 以其内存安全保证而闻名,但在某些特定场景中,您可能需要绕过部分检查。
Rust 中的 unsafe 关键字正是用于此目的。它并不是编写“糟糕”代码的方法,而是用于高级场景的工具,适用于需要更直接控制内存或硬件的情况。
不安全 Rust 的五种超能力
使用 unsafe 块时,您可以执行五种 Rust 编译器通常会阻止的特殊操作:
- 解引用裸指针:直接访问内存地址。
- 调用
unsafe函数或方法:执行带有编译器无法验证的前置条件的函数。 - 实现
unsafe特征:声明您的类型遵守特定不变量。 - 访问或修改可变静态变量:在全局范围共享可变状态,但可能引发数据竞争。
- 访问
union的字段:从联合体中读取数据,而该数据对于当前内容可能属于无效类型。
解引用裸指针
裸指针是没有 Rust 通常安全保证的内存地址。您可以从引用(&T、&mut T)创建裸指针,但解引用它们需要使用 unsafe 块。
这意味着您作为程序员,需要负责确保指针有效,并且指向已分配的内存。
fn main() {
let mut num = 5;
let r1 = &num as *const i32; // Immutable raw pointer
let r2 = &mut num as *mut i32; // Mutable raw pointer
unsafe { // The `unsafe` block starts here
println!("r1 points to: {}", *r1);
*r2 = 10; // Modify data through mutable raw pointer
println!("r2 points to: {}", *r2);
} // The `unsafe` block ends here
println!("Num is now: {}", num);
}调用不安全函数
某些函数会标记为 unsafe fn。这表示该函数具有 Rust 编译器无法保证的前置条件。例如,函数可能要求一个有效的内存地址,但无法验证该地址。
调用此类函数必须放在 unsafe 块中,以表明您作为调用者确保所有前置条件都已满足。
unsafe fn dangerous_operation() {
println!("This operation could be dangerous if preconditions aren't met!");
}
fn main() {
println!("Attempting a dangerous operation...");
unsafe { // Calling an unsafe function requires `unsafe`
dangerous_operation();
}
println!("Operation completed.");
}可变静态变量
Rust 默认会阻止全局可变状态,以避免数据竞争。不过,您可以使用 static mut 声明可变静态变量。
访问或修改这些变量被视为 unsafe,因为多个线程可能会同时尝试访问它们,从而导致未定义行为。您需要负责进行适当的同步。
static mut COUNTER: i32 = 0; // A mutable static variable
fn add_to_counter(inc: i32) {
unsafe { // Modifying `static mut` requires `unsafe`
COUNTER += inc;
}
}
fn main() {
add_to_counter(5);
unsafe { // Reading `static mut` also requires `unsafe`
println!("COUNTER after first add: {}", COUNTER);
}
add_to_counter(10);
unsafe {
println!("COUNTER after second add: {}", COUNTER);
}
}实现不安全特征
Rust 中的某些特征会标记为 unsafe trait。这表示实现它们时,必须遵守编译器无法检查的某些不变量。
常见示例是 Send 和 Sync 特征,它们与线程安全有关。如果您手动实现 unsafe trait,则必须使用 unsafe impl Trait for Type,并保证其安全属性。
对于大多数初学者来说,您不太常遇到这种情况,因为 Rust 通常会自动处理这些内容,或通过安全抽象来实现。
访问联合体字段
union 是一种特殊类型,在任意时刻可以保存其某个变体的值,但所有变体共享同一个内存位置。它类似于 C 语言中的联合体。
访问 union 的字段需要使用 unsafe 块,因为编译器无法知道当前哪个字段处于活动状态。读取未活动字段可能导致未定义行为或对数据的错误解释。
union Data {
integer: u32,
float: f32,
}
fn main() {
let mut d = Data { integer: 42 }; // Initialize with an integer
unsafe {
// Accessing 'integer' is safe here
println!("Integer value: {}", d.integer);
// Accessing 'float' is unsafe, as 'integer' was initialized.
// This would interpret the integer's bits as a float.
// println!("Float value (unsafe): {}", d.float);
}
d.float = 3.14; // Now initialize with a float
unsafe {
// Accessing 'float' is safe now
println!("Float value: {}", d.float);
}
}不安全 Rust 的实际场景
虽然应谨慎使用 unsafe,但它对于多项高级编程任务至关重要:
- 外部函数接口(FFI):与其他语言编写的代码(例如 C/C++ 库)交互。
- 性能优化:有时,绕过 Rust 的检查可以在关键代码段中带来少量性能提升(但请先进行测量!)。
- 底层系统编程:编写操作系统、设备驱动程序或嵌入式系统。
- 构建安全抽象:在不安全原语之上实现安全的数据结构或 API(例如
Vec的构建方式)。
使用不安全功能时的责任
使用 unsafe 时,您需要手动承担维护 Rust 安全保证的责任。这意味着:
- 确保内存有效且正确对齐。
- 处理共享可变状态时防止数据竞争。
- 避免悬空指针或释放后使用错误。
- 确保满足所有函数前置条件。
滥用 unsafe 可能导致未定义行为,这是最严重的一类错误,并且可能非常难以调试。
不安全知识检查
以下哪种操作在 Rust 中需要使用 unsafe 块?
回顾:不安全 Rust
您已经学习了不安全 Rust。这是一项强大功能,允许您在特定的高级场景中绕过 Rust 的部分编译时安全检查。
请记住,unsafe 并不会完全关闭借用检查器,而是将内存安全和不变量的责任完全转交给您——程序员。请谨慎并极其小心地使用它,通常将其用于 FFI、底层优化或构建安全抽象。
用 AI 导师学习 Rust — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 39
- 课程
- 144
常见问题解答
「与不安全 Rust 交互」课时是免费的吗?
是的 — 「与不安全 Rust 交互」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。
「与不安全 Rust 交互」这节课中我会学到什么?
了解何时以及如何使用 `unsafe` 代码块绕过 Rust 的安全检查,从而实现 FFI 和底层内存操作。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Learn Rust Coding 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 3 节。
「与不安全 Rust 交互」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Learn Rust Coding 课中编写并运行代码吗?
能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 声明式宏(`macro_rules!`)
- 过程宏:派生宏与函数宏
- 与不安全 Rust 交互