Skip to content

实战总结

> 综合运用引用知识,通过实战示例巩固不可变引用、可变引用的使用场景与最佳实践。

完整示例

示例 1:数据统计

rust
fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];

    // 不可变借用 - 只读
    let sum = calculate_sum(&numbers);
    let avg = calculate_average(&numbers);

    println!("总和:{},平均:{}", sum, avg);

    // 可变借用 - 修改
    double_all(&mut numbers);
    println!("翻倍后:{:?}", numbers);
}

fn calculate_sum(nums: &Vec<i32>) -> i32 {
    nums.iter().sum()
}

fn calculate_average(nums: &Vec<i32>) -> f64 {
    let sum: i32 = nums.iter().sum();
    *sum as f64 / nums.len() as f64
}

fn double_all(nums: &mut Vec<i32>) {
    for num in nums.iter_mut() {
        *num *= 2;
    }
}
▶ Run

示例 2:结构体修改器

rust
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let mut person = Person {
        name: String::from("Alice"),
        age: 25,
    };

    // 修改名字
    change_name(&mut person, "Bob");

    // 过生日
    celebrate_birthday(&mut person);

    // 打印信息(只读)
    print_info(&person);
}

fn change_name(person: &mut Person, new_name: &str) {
    person.name = new_name.to_string();
}

fn celebrate_birthday(person: &mut Person) {
    person.age += 1;
}

fn print_info(person: &Person) {
    println!("姓名:{},年龄:{}", person.name, person.age);
}
▶ Run

示例 3:字符串构建器

rust
fn main() {
    let mut buffer = String::with_capacity(100);

    // 逐步构建字符串
    append_line(&mut buffer, "第一行");
    append_line(&mut buffer, "第二行");
    append_line(&mut buffer, "第三行");

    // 统计信息(只读)
    let line_count = count_lines(&buffer);
    let char_count = count_chars(&buffer);

    println!("行数:{},字符数:{}", line_count, char_count);
    println!("内容:\n{}", buffer);
}

fn append_line(buffer: &mut String, content: &str) {
    buffer.push_str(content);
    buffer.push('\n');
}

fn count_lines(buffer: &String) -> usize {
    buffer.lines().count()
}

fn count_chars(buffer: &String) -> usize {
    buffer.chars().count()
}
▶ Run

常见错误

错误 1:忘记 mut

rust
fn main() {
    let s = String::from("hello");
    // s.push_str(" world");  // ❌ 错误:需要 mut

    let mut s = String::from("hello");
    s.push_str(" world");  // ✅ 正确
}
▶ Run

错误 2:可变引用使用时忘记 mut

rust
fn modify(s: &String) {
    // s.push_str(" world");  // ❌ 错误:需要&mut
}

fn modify_fixed(s: &mut String) {
    s.push_str(" world");  // ✅ 正确
}
▶ Run

错误 3:借用冲突

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

    let r1 = &s;
    let r2 = &mut s;  // ❌ 错误

    // 修复:分离使用
    println!("{}", r1);  // 先使用 r1

    // 现在 r1 不再使用,可以借用 mut
    let r2 = &mut s;
    r2.push_str(" world");
    println!("{}", r2);
}
▶ Run

错误 4:返回悬垂引用

rust
// ❌ 错误
// fn get_greeting() -> &String {
//     let s = String::from("hello");
//     &s
// }

// ✅ 正确:返回所有权
fn get_greeting() -> String {
    String::from("hello")
}
▶ Run

调试技巧

打印借用信息

rust
fn main() {
    let s = String::from("hello");
    let r = &s;

    println!("s 的地址:{:p}", &s);
    println!("r 的地址:{:p}", &r);
    println!("r 指向的地址:{:p}", r.as_ptr());
}
▶ Run

跟踪借用

rust
fn main() {
    let mut s = String::from("hello");
    println!("初始:{}", s);

    {
        let r = &mut s;
        println!("借用中:{}", r);
        r.push_str(" world");
    }  // 借用结束

    println!("借用结束后:{}", s);
}
▶ Run

练习

练习 1:不可变引用

创建函数 print_twice,接受字符串的引用并打印两次。

练习 2:可变引用

创建函数 clear_string,接受 String 的可变引用并清空它。

练习 3:借用规则实验

尝试以下代码,观察编译错误:

  1. 同时创建两个可变引用
  2. 同时创建可变和不可变引用
  3. 修复这些错误

小结

引用类型对比

类型语法数量能否修改用途
不可变引用&T任意只读访问
可变引用&mut T1 个修改数据

借用规则

  1. 同一时刻只能有一种借用

    • 多个不可变引用,或
    • 一个可变引用
  2. 引用不能比所有者存活更久

最佳实践

  1. 优先使用引用,避免不必要的所有权转移
  2. 使用 &str 而不是&String,更灵活
  3. 需要修改时使用&mut,否则使用不可变引用
  4. 借用范围尽量小,尽早释放借用

关键要点

  • 引用是"借用",不获取所有权
  • 借用规则防止数据竞争
  • 编译器确保引用安全
  • 自动解引用让代码更简洁

练习题

详见:练习题