Rust基础-part5-引用

发布于:2025-07-16 ⋅ 阅读:(19) ⋅ 点赞:(0)

Rust基础[part5]_引用

  • 不可变引用:通过不可变引用,可以读取变量,但是不能够修改数据。一个变量可以有多个不可变引用,但不能与可变引用共存。
  • 可变引用:通过可变引用,可以读取和修改数据。一个变量在某一时刻只能有一个可变引用,且不能与不可变引用共存。

引用规则

  • 同一时间(生命周期)内,一个变量只能有一个可变引用或多个不可变引用
    • 多个不可变引用可以共存
    • 可变引用必须是独占的(不能与其他引用共存)
  • 引用必须总是有效(Rust保证引用永远不会指向无效内存)

示例1:错误示范

pub fn reference_example() {
    let mut s: String = String::from("Hello");
    // 创建不可变引用
    let s1: &String = &s;
    // 创建可变引用(错误:此时s已有不可变引用)
    let s2: &mut String = &mut s;
  
    // 错误:不能创建多个可变引用
    let s3: &mut String = &mut s;
    
    // 错误:同一生命周期内同时使用不可变和可变引用
    println!("s1: {}, s2: {}", s1, s2); 
}

示例 2:正确示范

pub fn reference_example() {
    let mut s: String = String::from("Hello");
    
    // 第一阶段:仅使用不可变引用
    let s1: &String = &s;
    println!("s1: {}", s1); 
    // s1在此处不再使用
    
    // 第二阶段:创建可变引用(s1已不再活跃)
    let s2: &mut String = &mut s;
    println!("s2: {}", s2);
}

切片(Slices)

数组切片

 let a = [1, 2, 3];
    let b = & a[0..1];
    let c = & a[0..=1];

字符串切片

是对字符串部分内容的引用

// 字符串引用
    let s = String::from("Hello, Rust!");
    let slice1: &str = &s[0..5]; // "Hello"
    let slice2: &str = &s[7..]; // "Rust!"
    let slice3: &str = &s[..]; // "Hello, Rust!"

悬垂引用(Dangling Reference)

生命周期核心规则:引用的生命周期必须 ≤ 被引用对象的生命周期

错误示例1:

pub fn dangling_pointer_example() {
    let r: &String;
    {
        let s = String::from("Hello"); // s的生命周期仅在{}内
        r = &s;                        // r引用s,但s即将被销毁
    } // s在此处被释放
    println!("r: {}", r); // 错误:r引用的s已不存在(悬垂引用)
}

关键点

  • s的生命周期:从创建到}结束。
  • r的生命周期:从创建到函数结束(覆盖s的生命周期)。
  • 错误原因r存活时间超过s,导致引用无效。

错误示例2:

fn get_a() -> &String { // 错误:返回局部变量的引用
    let s = String::from("a");
    &s // 函数结束后s被销毁,引用悬空
}

关键点

  • 返回引用的合法性:只能返回参数全局变量的引用,不能返回局部变量的引用。

正确示例:

生命周期注解(Lifetime Annotation)

pub fn lifetime_example() {
    let large = longest("a", "ab");
    println!("The longest string is: {}", large);

    // 生命周期注解:确保返回的引用与参数生命周期一致
    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
        if x.len() > y.len() { x } else { y }
    }
}

关键点

  • 'a的含义:参数xy以及返回值的引用必须至少存活到'a结束
  • 编译器检查
    1. 验证xy的实际生命周期是否满足'a
    2. 确保返回值的生命周期不超过'a
  • 实际效果:返回的引用在调用者的作用域内有效(如large的生命周期覆盖longest的调用)。

总结:避免悬垂引用的3种方式

  1. 返回所有权(如fn get_a() -> String):转移值的控制权,无需引用。
  2. 引用外部变量(如fn get_a(s: &String) -> &String):确保被引用对象生命周期足够长。
  3. 生命周期注解(如fn longest<'a>(x: &'a str) -> &'a str):明确引用的合法存活范围。

网站公告

今日签到

点亮在社区的每一天
去签到