Skip to content

引用基础

> 理解引用(&T)如何借用值而不获取所有权,掌握不可变引用的基本用法。

为什么需要引用?

所有权的局限性

概念名称: 引用(Reference)允许借用值而不获取所有权。

语法结构:
┌──────────────────────────────────────┐
│  &T     → 不可变引用(只读)           │
│  &mut T → 可变引用(可读写)           │
│                                       │
│  let r = &s;      → 借用 s            │
│  let r = &mut s;  → 可变借用 s        │
└──────────────────────────────────────┘

最简示例

rust
fn main() {
    let s = String::from("hello");
    let r = &s;  // 借用,不移动所有权
    println!("{}", r);  // 通过引用访问
    println!("{}", s);  // s 仍然有效
}
▶ Run

详细示例

rust
// 问题:函数获取所有权后,原变量不能使用
fn main() {
    let s = String::from("hello");
    let len = string_length(s);  // s 的所有权被移动

    // println!("{}", s);  // ❌ 错误:s 已无效
    println!("长度:{}", len);
}

fn string_length(s: String) -> usize {
    s.len()
}
▶ Run

引用的解决方案

rust
// 使用引用:不转移所有权
fn main() {
    let s = String::from("hello");
    let len = string_length(&s);  // 只借用,不移动

    println!("'{}' 的长度是 {}", s, len);  // ✅ s 仍然有效
}

fn string_length(s: &String) -> usize {
    s.len()
}
▶ Run

引用 vs 所有权对比

┌─────────────────────────────────────────────────────┐
│           所有权传递 vs 引用借用                     │
├─────────────────────────────────────────────────────┤
│                                                     │
│  所有权传递(移动)                                  │
│  ┌──────┐         ┌──────┐                         │
│  │  main│         │函数  │                         │
│  │  s   │ ──────→ │  s   │                         │
│  │(无效)│         │(所有)│                         │
│  └──────┘         └──────┘                         │
│     ↑                ↓                              │
│   失去所有权      获得所有权                        │
│                                                     │
│  引用借用                                             │
│  ┌──────┐         ┌──────┐                         │
│  │  main│         │函数  │                         │
│  │  s   │ ──&s──→ │  &s  │                         │
│  │(所有)│         │(借用)│                         │
│  └──────┘         └──────┘                         │
│     ↑                ↓                              │
│   保持所有权      临时借用                          │
│                                                     │
└─────────────────────────────────────────────────────┘

不可变引用(&T)

引用语法

概念名称: &T 创建不可变引用(只读借用)。

语法结构:
┌──────────────────────────────────────┐
│  let 引用名 = &变量;                  │
│       ↑        ↑                      │
│       名字    借用操作符               │
│                                       │
│  let r = &s;     → r 借用 s          │
│  fn f(x: &T)     → 参数借用           │
│  &String::from() → 借用表达式结果     │
└──────────────────────────────────────┘

最简示例

rust
fn main() {
    let s = String::from("hello");
    let len = calculate_length(&s);
    println!("'{}' 长度 {}", s, len);
}

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

详细示例

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

    // 创建引用:使用 &
    let r1 = &s;
    let r2 = &s;

    // 使用引用
    println!("r1: {}", r1);
    println!("r2: {}", r2);

    // 原变量仍然有效
    println!("s: {}", s);
}
▶ Run

函数参数中的引用

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

    // 传递引用
    let len = calculate_length(&s);

    // s 仍然可用
    println!("'{}' 的长度是 {}", s, len);
}

fn calculate_length(s: &String) -> usize {
    // 通过引用访问数据
    s.len()
}  // s 离开作用域,但不释放内存
▶ Run

内存布局图解

创建引用前:
栈(Stack)                  堆(Heap)
┌─────────────┐            ┌─────────┐
│    s        │            │"hello"  │
│ ┌───┬───┬─┐ │            │         │
│ │ptr│len│cap│─┼─────────→│         │
│ └───┴───┴─┘ │            └─────────┘
└─────────────┘

创建引用 &s 后:
栈(Stack)                  堆(Heap)
┌─────────────┐            ┌─────────┐
│    s        │            │"hello"  │
│ ┌───┬───┬─┐ │            │         │
│ │ptr│len│cap│─┼─────┬───→│         │
│ └───┴───┴─┘ │      │     └─────────┘
└─────────────┘      │
┌─────────────┐      │
│   &s (r1)   │──────┘
│ ┌───┬───┬─┐ │
│ │ptr│len│cap│ │
│ └───┴───┴─┘ │
└─────────────┘

关键点:
• &s 也是一个(指针,长度,容量)结构
• 它指向 s 的数据,但不拥有它
• s 负责在作用域结束时释放数据

多个不可变引用

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

    // 可以同时有多个不可变引用
    let r1 = &s;
    let r2 = &s;
    let r3 = &s;

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

    // 原变量也可以使用
    println!("s: {}", s);
}
▶ Run

小结

  • 引用(&T)是"借用",不获取所有权,原变量仍可使用
  • 多个不可变引用可以同时存在(只读访问)
  • 函数参数使用引用可避免所有权转移
  • 内存布局:引用指向数据但不拥有数据

练习题

详见:练习题