Rust所有权系统Skill rust-ownership-system

Rust所有权系统是Rust编程语言的核心内存管理机制,通过编译时检查确保内存安全,无需垃圾回收。它涉及所有权规则、移动语义、借用、生命周期和智能指针等概念,用于编写高效、安全的系统级代码,特别是在嵌入式开发、操作系统和性能关键应用中。关键词:Rust, 所有权, 内存安全, 借用, 生命周期, 编译时检查, 内存管理, 智能指针, 系统编程。

嵌入式软件 0 次安装 0 次浏览 更新于 3/25/2026

name: rust-ownership-system user-invocable: false description: 当使用Rust的所有权系统时使用,包括所有权规则、借用、生命周期和内存安全。当处理Rust内存管理时使用。 allowed-tools:

  • Bash
  • Read

Rust所有权系统

掌握Rust独特的所有权系统,通过编译时检查提供内存安全,无需垃圾回收。

所有权规则

三个基本所有权规则:

  1. Rust中的每个值都有一个变量作为其所有者
  2. 同一时间只能有一个所有者
  3. 当所有者离开作用域时,值被丢弃
fn ownership_basics() {
    // s 拥有这个 String
    let s = String::from("hello");

    // 所有权移动到 s2
    let s2 = s;

    // 错误:s 不再拥有该值
    // println!("{}", s);

    println!("{}", s2); // 正常
} // s2 在这里被丢弃,内存释放

移动语义

所有权转移(移动):

fn move_semantics() {
    let s1 = String::from("hello");

    // 所有权移动到函数
    takes_ownership(s1);

    // 错误:s1 不再有效
    // println!("{}", s1);
}

fn takes_ownership(s: String) {
    println!("{}", s);
} // s 在这里被丢弃

// 从函数返回所有权
fn gives_ownership() -> String {
    String::from("hello")
}

fn main() {
    let s = gives_ownership();
    println!("{}", s);
}

栈类型的Copy trait:

fn copy_types() {
    // 实现Copy的类型被复制,而不是移动
    let x = 5;
    let y = x; // x 复制到 y

    println!("x: {}, y: {}", x, y); // 两者都有效

    // Copy类型:整数、浮点数、布尔值、字符、由Copy类型组成的元组
    let tuple = (1, 2.5, true);
    let tuple2 = tuple;
    println!("{:?} {:?}", tuple, tuple2); // 两者都有效
}

借用

不可变借用(引用):

fn immutable_borrow() {
    let s1 = String::from("hello");

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

    println!("Length of '{}' is {}", s1, len); // s1 仍然有效
}

fn calculate_length(s: &String) -> usize {
    s.len()
} // s 离开作用域,但不丢弃值

// 允许多个不可变借用
fn multiple_immutable_borrows() {
    let s = String::from("hello");

    let r1 = &s;
    let r2 = &s;
    let r3 = &s;

    println!("{}, {}, {}", r1, r2, r3); // 正常
}

可变借用:

fn mutable_borrow() {
    let mut s = String::from("hello");

    // 可变借用
    change(&mut s);

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

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

// 同一时间只允许一个可变借用
fn mutable_borrow_rules() {
    let mut s = String::from("hello");

    let r1 = &mut s;
    // let r2 = &mut s; // 错误:不能可变借用两次

    println!("{}", r1);
}

// 不能混合可变和不可变借用
fn no_mix_borrows() {
    let mut s = String::from("hello");

    let r1 = &s;     // 不可变借用
    let r2 = &s;     // 另一个不可变借用
    // let r3 = &mut s; // 错误:当不可变借用时不能可变借用

    println!("{} {}", r1, r2);
}

非词法生命周期(NLL):

fn non_lexical_lifetimes() {
    let mut s = String::from("hello");

    let r1 = &s;
    let r2 = &s;
    println!("{} {}", r1, r2);
    // r1 和 r2 在此点后不再使用

    // 正常:不可变借用已结束
    let r3 = &mut s;
    println!("{}", r3);
}

生命周期

生命周期注解:

// 生命周期 'a 确保返回的引用与两个输入一样长
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");
    let string2 = String::from("short");

    let result = longest(&string1, &string2);
    println!("Longest: {}", result);
}

结构体中的生命周期:

// 结构体持有引用,需要生命周期注解
struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }

    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention: {}", announcement);
        self.part
    }
}

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

    let excerpt = ImportantExcerpt {
        part: first_sentence,
    };

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

生命周期省略规则:

// 编译器在这些情况下推断生命周期:

// 规则1:每个引用参数获得自己的生命周期
fn first_word(s: &str) -> &str {
    // 扩展:fn first_word<'a>(s: &'a str) -> &'a str
    s.split_whitespace().next().unwrap_or("")
}

// 规则2:如果有一个输入生命周期,分配给所有输出
fn foo(s: &str) -> &str {
    s
}

// 规则3:如果有 &self 或 &mut self,其生命周期分配给输出
impl<'a> ImportantExcerpt<'a> {
    fn get_part(&self) -> &str {
        // 扩展:fn get_part<'a>(&'a self) -> &'a str
        self.part
    }
}

静态生命周期:

// 'static 意味着引用在整个程序期间存在
fn static_lifetime() -> &'static str {
    "This string is stored in binary"
}

// 字符串字面量有 'static 生命周期
let s: &'static str = "hello world";

智能指针

Box用于堆分配:

fn box_pointer() {
    // 在堆上分配值
    let b = Box::new(5);
    println!("b = {}", b);
} // b 在离开作用域时释放

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

use List::{Cons, Nil};

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

Rc用于引用计数:

use std::rc::Rc;

fn rc_example() {
    let a = Rc::new(5);

    // 克隆 Rc 指针,增加计数
    let b = Rc::clone(&a);
    let c = Rc::clone(&a);

    println!("Reference count: {}", Rc::strong_count(&a)); // 3

    // 所有所有者必须离开作用域后值才被丢弃
}

// 在图结构中共享数据
enum RcList {
    Cons(i32, Rc<RcList>),
    Nil,
}

use RcList::{Cons as RcCons, Nil as RcNil};

fn shared_ownership() {
    let a = Rc::new(RcCons(5, Rc::new(RcCons(10, Rc::new(RcNil)))));

    // b 和 c 都引用 a
    let b = RcCons(3, Rc::clone(&a));
    let c = RcCons(4, Rc::clone(&a));
}

RefCell用于内部可变性:

use std::cell::RefCell;

fn refcell_example() {
    let value = RefCell::new(5);

    // 可变借用
    *value.borrow_mut() += 1;

    // 不可变借用
    println!("Value: {}", value.borrow());
}

// 结合 Rc 和 RefCell 用于共享可变数据
use std::rc::Rc;
use std::cell::RefCell;

fn rc_refcell() {
    let value = Rc::new(RefCell::new(5));

    let a = Rc::clone(&value);
    let b = Rc::clone(&value);

    *a.borrow_mut() += 10;
    *b.borrow_mut() += 20;

    println!("Value: {}", value.borrow()); // 35
}

所有权模式

获取所有权 vs 借用:

// 当需要消耗值时获取所有权
fn consume(s: String) {
    println!("{}", s);
}

// 当只需要读取时借用
fn read(s: &String) {
    println!("{}", s);
}

// 当需要修改时可变借用
fn modify(s: &mut String) {
    s.push_str(" modified");
}

fn main() {
    let mut s = String::from("hello");

    read(&s);        // 仍然拥有 s
    modify(&mut s);  // 仍然拥有 s
    consume(s);      // 不再拥有 s
}

构建器模式与所有权:

struct Config {
    name: String,
    value: i32,
}

struct ConfigBuilder {
    name: Option<String>,
    value: Option<i32>,
}

impl ConfigBuilder {
    fn new() -> Self {
        ConfigBuilder {
            name: None,
            value: None,
        }
    }

    // 获取所有权并返回所有权
    fn name(mut self, name: String) -> Self {
        self.name = Some(name);
        self
    }

    fn value(mut self, value: i32) -> Self {
        self.value = Some(value);
        self
    }

    fn build(self) -> Config {
        Config {
            name: self.name.unwrap_or_default(),
            value: self.value.unwrap_or(0),
        }
    }
}

fn main() {
    let config = ConfigBuilder::new()
        .name(String::from("app"))
        .value(42)
        .build();
}

切片类型

字符串切片:

fn string_slices() {
    let s = String::from("hello world");

    // 切片引用字符串的一部分
    let hello = &s[0..5];
    let world = &s[6..11];

    // 简写
    let hello = &s[..5];
    let world = &s[6..];
    let whole = &s[..];

    println!("{} {}", hello, world);
}

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

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

    &s[..]
}

数组切片:

fn array_slices() {
    let a = [1, 2, 3, 4, 5];

    let slice = &a[1..3]; // &[i32]

    assert_eq!(slice, &[2, 3]);
}

Clone vs Copy

理解Clone trait:

#[derive(Clone)]
struct Point {
    x: f64,
    y: f64,
}

fn clone_example() {
    let p1 = Point { x: 1.0, y: 2.0 };

    // 显式克隆(深拷贝)
    let p2 = p1.clone();

    // 两者都有效
    println!("{} {}", p1.x, p2.x);
}

Copy trait限制:

// Copy 要求所有字段实现 Copy
#[derive(Copy, Clone)]
struct Coord {
    x: i32,
    y: i32,
}

// 不能为包含 String 字段的类型派生 Copy
// #[derive(Copy, Clone)]  // 错误
struct Person {
    name: String,  // String 不实现 Copy
}

Drop Trait

使用Drop自定义清理:

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data: {}", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };

    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };

    println!("CustomSmartPointers created");
} // d 被丢弃,然后 c 被丢弃

手动drop:

fn manual_drop() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };

    println!("Before drop");
    drop(c); // 手动提前丢弃
    println!("After drop");
}

何时使用此技能

使用 rust-ownership-system 当您需要:

  • 理解Rust的内存管理模型
  • 编写无需垃圾回收的内存安全代码
  • 处理函数间的所有权转移
  • 使用引用和借用
  • 实现带有生命周期参数的结构体
  • 使用智能指针(Box、Rc、RefCell)
  • 调试借用检查器错误
  • 选择所有权、借用和克隆
  • 实现自定义Drop行为
  • 安全地使用切片和引用

最佳实践

  • 可能时优先借用而非所有权转移
  • 默认使用不可变借用,仅在需要时使用可变借用
  • 尽可能缩小借用范围
  • 当编译器能推断生命周期时使用生命周期省略
  • 根据用例选择合适的智能指针
  • 在性能关键代码中避免使用RefCell
  • 在函数签名中使用切片而非自有类型
  • 仅在必要时克隆(它是显式和可见的)
  • 为自定义清理逻辑实现Drop
  • 让借用检查器错误指导您

常见陷阱

  • 移动值后尝试使用它
  • 同时创建多个可变借用
  • 混合可变和不可变借用
  • 返回局部变量的引用
  • 对抗借用检查器而非理解它
  • 过度使用clone()以避免所有权问题
  • 不理解生命周期关系
  • 使用Rc时的循环引用(使用Weak)
  • 在运行时因RefCell借用违规而panic
  • 错误使用 'static 生命周期

资源