《深入Rust系统编程》2.3 所有权与生命周期

所有权和生命周期是 Rust 语言中两个独特且强大的概念,它们共同构成了 Rust 内存安全的基础。理解所有权和生命周期对于编写安全、高效的 Rust 程序至关重要。

2.3 所有权与生命周期

所有权和生命周期是 Rust 语言中两个独特且强大的概念,它们共同构成了 Rust 内存安全的基础。理解所有权和生命周期对于编写安全、高效的 Rust 程序至关重要。

2.3.1 所有权

所有权系统是 Rust 最显著的特点之一,它规定了 Rust 中值的所有权关系,确保内存安全。

1. 所有权规则:

  • 每个值都有一个所有者。 值的所有者负责释放该值占用的内存。
  • 值在同一时间只能有一个所有者。 当值的所有者离开作用域时,值将被自动释放。
  • 可以通过移动 (move) 或借用 (borrow) 来转移或共享值的所有权。

2. 移动语义:

当将一个值赋值给另一个变量时,Rust 会将该值的所有权移动到新的变量,原变量将不再有效。

let s1 = String::from("hello");
let s2 = s1; // s1 的所有权移动到 s2
println!("{}", s1); // 错误!s1 不再有效

3. 借用:

为了避免移动所有权,可以使用借用。借用允许在不转移所有权的情况下访问值。

  • 不可变借用 (&T): 允许读取值,但不能修改值。
  • 可变借用 (&mut T): 允许读取和修改值。
let s1 = String::from("hello");
let len = calculate_length(&s1); // 不可变借用 s1
println!("The length of '{}' is {}.", s1, len);

fn calculate_length(s: &String) -> usize {
    s.len()
}

4. 借用规则:

  • 在任意给定时间,要么只能有一个可变借用,要么只能有多个不可变借用。
  • 借用必须始终有效。

2.3.2 生命周期

生命周期是 Rust 用来确保引用始终有效的机制。生命周期注解用于指定引用的有效范围。

1. 生命周期注解:

生命周期注解使用单引号 (') 表示,例如 'a

&i32        // 一个引用
&'a i32     // 一个带有显式生命周期的引用
&'a mut i32 // 一个带有显式生命周期的可变引用

2. 函数签名中的生命周期注解:

当函数返回引用时,需要指定生命周期注解,以确保返回的引用有效。

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

3. 结构体定义中的生命周期注解:

当结构体包含引用时,需要指定生命周期注解,以确保结构体实例中的引用有效。

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
}

2.3.3 代码实例

1. 所有权转移:

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // s1 的所有权移动到 s2
    // println!("{}", s1); // 错误!s1 不再有效
    println!("{}", s2); // 输出 "hello"
}

2. 不可变借用:

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1); // 不可变借用 s1
    println!("The length of '{}' is {}.", s1, len); // 输出 "The length of 'hello' is 5."
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

3. 可变借用:

fn main() {
    let mut s = String::from("hello");
    change(&mut s); // 可变借用 s
    println!("{}", s); // 输出 "hello, world"
}

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

4. 函数签名中的生命周期注解:

fn main() {
    let string1 = String::from("long string is long");
    let string2 = "xyz";
    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result); // 输出 "The longest string is long string is long"
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

5. 结构体定义中的生命周期注解:

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
    println!("{}", i.part); // 输出 "Call me Ishmael"
}

2.3.4 总结

所有权和生命周期是 Rust 内存安全的核心机制。理解所有权规则、借用规则和生命周期注解,对于编写安全、高效的 Rust 程序至关重要。Rust 的所有权系统有效地防止了内存泄漏和数据竞争,而生命周期机制则确保了引用的有效性。掌握所有权和生命周期的使用技巧,可以编写出更安全、更可靠的 Rust 代码。

以下是一些学习 Rust 所有权和生命周期的资源:

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页