引言

Rust通过独特的所有权系统在编译阶段保证内存安全,无需垃圾回收器,也无需手动管理内存。这种设计使Rust能够在提供C/C++级别性能的同时,避免常见的内存安全漏洞。本文将深入剖析Rust的内存安全机制。

一、所有权系统基础

1.1 所有权规则

Rust有三条核心的所有权规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 规则1:每个值有一个所有者
let s = String::from("hello");  // s是字符串的所有者

// 规则2:同一时间只能有一个所有者
let s1 = s;  // s的所有权转移给s1,s不再有效
// println!("{}", s);  // 编译错误:value borrowed here after move

// 规则3:所有者离开作用域,值被丢弃
{
    let s2 = String::from("world");
}  // s2在这里被自动drop

1.2 移动语义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 基本类型实现了Copy trait,赋值是拷贝
let x = 5;
let y = x;  // x仍然有效
println!("x = {}, y = {}", x, y);

// String没有实现Copy,赋值是移动
let s1 = String::from("hello");
let s2 = s1;  // s1被移动到s2
// println!("{}", s1);  // 编译错误

// 使用clone()进行深拷贝
let s3 = String::from("world");
let s4 = s3.clone();  // 显式克隆
println!("s3 = {}, s4 = {}", s3, s4);

1.3 函数调用中的所有权

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
fn main() {
    let s = String::from("hello");

    // 所有权传递给函数
    takes_ownership(s);
    // println!("{}", s);  // 编译错误:s已被移动

    let x = 5;
    // Copy类型传递拷贝
    makes_copy(x);
    println!("x = {}", x);  // x仍然有效

    // 函数返回所有权
    let s2 = gives_ownership();
    println!("{}", s2);
}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
}  // some_string在这里被drop

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
}

fn gives_ownership() -> String {
    let some_string = String::from("yours");
    some_string  // 返回所有权
}

二、借用与引用

2.1 不可变借用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn main() {
    let s1 = String::from("hello");

    // 创建不可变引用
    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
    // s1仍然有效,因为我们只是借用
}

fn calculate_length(s: &String) -> usize {
    s.len()
}  // s离开作用域,但因为没有所有权,所以不会drop

2.2 可变借用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn main() {
    let mut s = String::from("hello");

    // 创建可变引用
    change(&mut s);

    println!("{}", s);  // 输出: hello, world
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

2.3 借用规则

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
    let mut s = String::from("hello");

    // 规则1:同一时间可以有多个不可变引用
    let r1 = &s;
    let r2 = &s;
    println!("{} and {}", r1, r2);
    // r1和r2在这里不再使用

    // 规则2:同一时间只能有一个可变引用
    let r3 = &mut s;
    // let r4 = &mut s;  // 编译错误:不能有多个可变引用
    println!("{}", r3);

    // 规则3:不可变引用和可变引用不能同时存在
    let r5 = &s;
    // let r6 = &mut s;  // 编译错误
    println!("{}", r5);
    let r6 = &mut s;  // r5不再使用,可以创建可变引用
}

2.4 悬垂引用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 编译错误:返回指向已释放内存的引用
fn dangle() -> &String {  // 编译错误
    let s = String::from("hello");
    &s  // 返回指向s的引用,但s将被drop
}  // s在这里被drop,内存被释放

// 正确的做法:返回String
fn no_dangle() -> String {
    let s = String::from("hello");
    s  // s的所有权被移动出去
}

三、生命周期

3.1 生命周期注解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 生命周期注解语法
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("long string is long");
    let string2 = String::from("xyz");

    let result = longest(string1.as_str(), string2.as_str());
    println!("The longest string is {}", result);
}

3.2 结构体中的生命周期

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 结构体引用的生命周期
struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().unwrap();

    let i = ImportantExcerpt {
        part: first_sentence,
    };

    println!("{}", i.part);
}

3.3 生命周期省略规则

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 规则1:每个引用参数都有自己的生命周期
fn first_word<'a>(s: &'a str) -> &'a str {
    // 编译器自动添加生命周期
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

// 等价于
fn first_word(s: &str) -> &str {
    // 编译器应用省略规则
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}

// 规则2:如果只有一个输入生命周期,则赋予所有输出生命周期
// 规则3:如果有多个输入生命周期,但其中一个是&self或&mut self,
//        则赋予所有输出生命周期

3.4 静态生命周期

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 'static生命周期存活于整个程序运行期间
let s: &'static str = "I have a static lifetime.";

// 示例:在结构体中使用
struct Config<'a> {
    app_name: &'static str,
    data: &'a str,
}

fn main() {
    let data = String::from("some data");
    let config = Config {
        app_name: "MyApp",
        data: &data,
    };
}

四、智能指针

4.1 Box - 堆分配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 在堆上存储数据
fn main() {
    let b = Box::new(5);
    println!("b = {}", b);

    // 递归类型
    enum List {
        Cons(i32, Box<List>),
        Nil,
    }

    use List::{Cons, Nil};

    let list = Cons(1,
        Box::new(Cons(2,
            Box::new(Cons(3,
                Box::new(Nil)
            ))
        ))
    );
}

4.2 Rc - 引用计数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    println!("count after creating a = {}", Rc::strong_count(&a));

    let b = Rc::clone(&a);
    println!("count after creating b = {}", Rc::strong_count(&a));

    {
        let c = Rc::clone(&a);
        println!("count after creating c = {}", Rc::strong_count(&a));
    }

    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

4.3 Arc - 线程安全引用计数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use std::sync::Arc;
use std::thread;

fn main() {
    let a = Arc::new(5);
    let b = Arc::clone(&a);

    let handle = thread::spawn(move || {
        println!("Thread: value = {}", b);
    });

    println!("Main: value = {}", a);
    handle.join().unwrap();
}

4.4 RefCell - 内部可变性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use std::cell::RefCell;

fn main() {
    let data = RefCell::new(5);

    // 获取多个不可变引用
    *data.borrow() = 10;
    println!("{}", data.borrow());

    // 获取可变引用
    *data.borrow_mut() = 20;
    println!("{}", data.borrow());
}

五、并发与线程安全

5.1 Send和Sync trait

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Send:可以在线程间转移所有权
// Sync:可以在线程间共享引用

// 大多数类型实现了Send和Sync
// Rc<T>不是Send也不是Sync
// Arc<T>是Send和Sync

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

5.2 通道通信

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("hi");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}

六、内存布局与性能

6.1 栈与堆

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    // 栈分配:固定大小,编译时已知
    let x: i32 = 5;
    let y: bool = true;
    let z: char = 'a';

    // 堆分配:动态大小
    let s1: String = String::from("hello");
    let s2: Box<i32> = Box::new(42);

    // String的内存布局
    // 栈上:ptr(8字节) | len(8字节) | capacity(8字节)
    // 堆上:实际字符串数据
}

6.2 零成本抽象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 迭代器示例:编译器会优化掉抽象开销
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];

    // 高级抽象
    let sum: i32 = numbers.iter()
        .map(|x| x * 2)
        .filter(|x| x > &5)
        .sum();

    println!("Sum: {}", sum);

    // 编译后生成的代码与手写循环同样高效
    // 零成本抽象:编译期优化移除所有抽象开销
}

6.3 内联与优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 函数可能被内联
#[inline]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 强制内联
#[inline(always)]
fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

// 禁止内联
#[inline(never)]
fn complex_calculation(x: i32) -> i32 {
    // 复杂计算
    x * 2 + 1
}

fn main() {
    let result = add(1, 2);
    // 编译器可能内联为:let result = 1 + 2;
}

七、错误处理

7.1 Result<T, E>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut username = String::new();

    File::open("username.txt")?.read_to_string(&mut username)?;

    Ok(username)
}

// 等价于上面的代码,使用?运算符
fn read_username_from_file_v2() -> Result<String, io::Error> {
    let mut username = String::new();
    let mut file = File::open("username.txt")?;
    file.read_to_string(&mut username)?;
    Ok(username)
}

// 链式调用
fn read_username_from_file_v3() -> Result<String, io::Error> {
    let mut username = String::new();
    File::open("username.txt")?.read_to_string(&mut username)?;
    Ok(username)
}

7.2 Option

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;

    // 使用match处理Option
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    // 使用if let简化
    if let Some(i) = some_number {
        println!("The number is {}", i);
    }

    // 使用map和and_then组合
    let result = some_number
        .map(|i| i * 2)
        .and_then(|i| if i > 5 { Some(i) } else { None });
}

八、高级特性

8.1 trait对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
trait Draw {
    fn draw(&self);
}

struct Button {
    width: u32,
    height: u32,
}

impl Draw for Button {
    fn draw(&self) {
        println!("Drawing button {}x{}", self.width, self.height);
    }
}

struct TextField {
    text: String,
}

impl Draw for TextField {
    fn draw(&self) {
        println!("Drawing text: {}", self.text);
    }
}

fn main() {
    let components: Vec<Box<dyn Draw>> = vec![
        Box::new(Button { width: 50, height: 10 }),
        Box::new(TextField { text: String::from("Hello") }),
    ];

    for component in components {
        component.draw();
    }
}

8.2 闭包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fn main() {
    // 闭包捕获环境变量
    let x = 4;

    // 不可变借用
    let equal_to_x = |z| z == x;
    println!("{}", equal_to_x(4));

    // 可变借用
    let mut x = 4;
    let mut borrow_mutably = || x += 1;
    borrow_mutably();
    println!("x = {}", x);

    // 获取所有权
    let x = vec![1, 2, 3];
    let consume = || {
        let _x = x;
        // x被移动到闭包中
    };
    consume();

    // 闭包作为参数
    fn apply<F>(f: F, value: i32) -> i32
    where
        F: Fn(i32) -> i32,
    {
        f(value)
    }

    let double = |x| x * 2;
    println!("{}", apply(double, 5));
}

8.3 迭代器适配器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];

    // map
    let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();

    // filter
    let evens: Vec<&i32> = numbers.iter().filter(|&x| x % 2 == 0).collect();

    // fold
    let sum: i32 = numbers.iter().fold(0, |acc, x| acc + x);

    // 链式操作
    let result: Vec<i32> = numbers.iter()
        .filter(|&&x| x > 2)
        .map(|&x| x * 2)
        .take(2)
        .collect();

    println!("Result: {:?}", result);  // [6, 8]
}

总结

Rust的内存安全机制核心要点:

  1. 所有权系统 - 编译时保证内存安全,无需垃圾回收
  2. 借用检查 - 在编译时防止数据竞争
  3. 生命周期 - 确保引用始终有效
  4. 智能指针 - 灵活的内存管理方式
  5. 零成本抽象 - 高级抽象不影响运行时性能

这些特性使Rust能够在不牺牲性能的前提下,提供内存安全和并发安全的保证。

相关工具推荐