Skip to content

引用进阶

> 学习悬垂引用的预防、解引用操作符的用法,以及函数参数中 &str 与 &String 的最佳实践选择。

悬垂引用(Dangling Reference)

什么是悬垂引用?

悬垂引用 = 指向已释放内存的引用

危险:
1. 访问无效内存
2. 程序崩溃
3. 安全漏洞

Rust 如何防止

rust
// ❌ 错误:返回悬垂引用
// fn create_dangle() -> &String {
//     let s = String::from("hello");
//     &s  // s 在函数结束时被释放
// }
▶ Run

错误信息:

error[E0515]: cannot return reference to local variable `s`
 --> src/main.rs:4:5
  |
4 |     &s
  |     ^^ returns a reference to data owned by the current function

正确的做法

rust
// 方案 1:返回所有权
fn create_string() -> String {
    String::from("hello")
}

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

// 方案 2:使用静态生命周期
fn get_static() -> &'static str {
    "hello"  // 字符串字面量,整个程序生命周期
}

fn main() {
    let s = get_static();
    println!("{}", s);
}
▶ Run

解引用操作符(*)

基本用法

rust
fn main() {
    let x = 5;
    let y = &x;  // y 是引用

    assert_eq!(5, x);
    assert_eq!(5, *y);  // *y 解引用,获取值
}
▶ Run

内存图解

栈:
┌──────┐
│  x=5 │
└──────┘


┌──────┐
│  y   │  → 指向 x
└──────┘

*y = 5(跟随指针获取值)

自动解引用(Deref Coercion)

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

    // Rust 会自动解引用
    r.push_str(", world");

    // 等价于显式解引用
    (*r).push_str("!");

    println!("{}", s);
}
▶ Run

何时需要显式解引用

rust
fn main() {
    let x = 5;
    let y = &x;

    // 需要显式解引用的情况
    let z = *y + 1;  // z = 6

    // 不需要解引用的情况
    println!("{}", y);  // Rust 自动解引用
    assert_eq!(5, y);   // Rust 自动解引用
}
▶ Run

&str vs &String

最佳实践:使用 &str

rust
// ❌ 不推荐:只接受 &String
fn greet_string(s: &String) {
    println!("Hello, {}!", s);
}

// ✅ 推荐:接受 &str
fn greet_str(s: &str) {
    println!("Hello, {}!", s);
}

fn main() {
    let owned = String::from("Alice");
    let borrowed = "Bob";

    // &String 函数只能接受 String 的引用
    greet_string(&owned);
    // greet_string(borrowed);  // ❌ 错误

    // &str 函数可以接受多种类型
    greet_str(&owned);    // &String → &str(自动转换)
    greet_str(borrowed);  // &'static str
    greet_str(&owned[0..3]);  // 切片也是&str
}
▶ Run

为什么 &str 更灵活

类型转换关系:

String ──────→ &str  (通过 Deref)
  ↓                      ↑
  │                      │
  │                      │
&String ─────→ &str  (通过 Deref coercion)


结论:&str 是"通用接口",可以接受:
• 字符串字面量
• String 的引用
• 字符串切片

小结

  • Rust 编译器阻止悬垂引用,返回局部变量引用会编译失败
  • * 解引用操作符获取引用指向的值,多数情况自动解引用
  • 函数参数优先使用 &str 而非 &String,更通用灵活
  • Deref coercion 让 &String 自动转换为 &str

练习题

详见:练习题