Appearance
13.2 内存不安全示例:修改枚举
Rust 设计的这个原则,究竟有没有必要呢?它又是如何在实际代码中起到“内存安全”检查作用的呢?
第一个示例,我们用 enum 来说明。假如我们有一个枚举类型:
rust
enum StringOrInt {
Str(String),
Int(i64),
}
它有两个元素,分别可以携带 String 类型的信息以及 i64 类型的信息。假如我们有一个引用指向了它的内部数据,同时再修改这个变量,大家猜想会发生什么情况?这样做可能会出现内存安全问题,因为我们有机会用一个 String 类型的指针指向 i64 类型的数据,或者用一个 i64 类型的指针指向 String 类型的数据。完整示例如下:
rust
use std::fmt::Debug;
#[derive(Debug)]
enum StringOrInt {
Str(String),
Int(i64),
}
fn main() {
use StringOrInt::{Str, Int};
let x = Str("Hello world".to_string());
if let Str(ref insides) = x {
x = Int(1);
println!("inside is {}, x says: {:?}", insides, x);
}
}
在这段代码中,我们用if let
语法创建了一个指向内部 String 的指针,然后在此指针的生命周期内,再把x
内部数据变成 i64 类型。这是典型的内存不安全的场景。
幸运的是,这段代码编译不通过,错误信息为:
error[E0506]: cannot assign to `x` because it is borrowed
这个例子给了我们一个直观的感受,为什么 Rust 需要“可变性和共享性不能同时存在”的规则?保证当前只有一个访问入口,这是保证安全的可靠做法。