Ownership, Borrowing & Lifetimes

Ownership and moves, references and borrowing, lifetimes, smart pointers (Box/Rc/Arc), and interior mutability with RefCell/Mutex.

IntermediateUpdated 2026-10-2946K views

Ownership and Moves

fn main() {
    let s1 = String::from("hi");
    let s2 = s1;            // 移动:s1 失效(堆数据只有一个主人)
    // println!("{}", s1);  // ✗ borrow of moved value
    println!("{}", s2);

    // Copy 类型(栈上):i32、f64、bool、(i32, i32) 等直接复制
    let a = 5;
    let b = a;              // a 仍可用
}

// 函数传参同样是移动(或借用)
fn takes(s: String) { /* s 在函数结束时 drop */ }
fn borrows(s: &String) { /* 只读,不获取所有权 */ }
fn gives() -> String { String::from("hi") }   // 所有权交出

When the compile error 'does not live long enough' or 'borrow of moved value' appears, the fix is usually one of: borrow with &, clone if cheap, or restructure so ownership flows one direction.

Lifetimes

// 编译器需要证明返回的引用不会悬空
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

let s1 = String::from("long string");
let res;              // res 的生命周期被 'a 约束
{
    let s2 = String::from("x");
    // res = longest(s1.as_str(), s2.as_str());
    // ✗ s2 活不到 res 使用的地方
}
// println!("{}", res);

// 结构体持有引用必须标注
struct Parser<'a> {
    src: &'a str,
}
let p = Parser { src: &s1 };    // p 不能比 s1 活得久

// 匿名生命周期 '_:签名里 'a 太吵时用来简化
fn first_word(s: &str) -> &str { s }
Lifetime elision handles the common cases (one input ref → same output ref); explicit annotations are needed when there are two or more input references or a struct holds references.

Smart Pointers

类型语义何时使用
Box<T>独占堆分配递归类型、大数据、trait 对象
Rc<T>单线程引用计数树/图结构,多个所有者
Arc<T>原子引用计数跨线程共享(线程安全版 Rc)
RefCell<T>运行时借用检查单线程内部可变性
Mutex<T>运行时互斥跨线程内部可变性
Cow<'a, T>写时克隆可能修改也可能只读的输入
use std::sync::{Arc, Mutex};

// 多线程共享可变计数:Arc + Mutex
let counter = Arc::new(Mutex::new(0));

let mut handles = vec![];
for _ in 0..10 {
    let c = Arc::clone(&counter);
    handles.push(std::thread::spawn(move || {
        let mut n = c.lock().unwrap();
        *n += 1;
    }));
}
for h in handles { h.join().unwrap(); }
println!("{}", *counter.lock().unwrap());   // 10

// Box 构建 trait 对象(动态分发)
let animal: Box<dyn Animal> = Box::new(Dog);

Error Handling: Result and the ? Operator

use std::fs;
use std::io;

// ? 运算符:出错即早退
fn read_config(path: &str) -> io::Result<String> {
    let raw = fs::read_to_string(path)?;      // 失败则 return Err
    Ok(raw.trim().to_string())
}

// 自定义错误:thiserror(库)或 anyhow(应用)
// #[derive(thiserror::Error, Debug)]
// pub enum ShopError { #[error("not found")] NotFound }

fn main() {
    match read_config("app.toml") {
        Ok(cfg) => println!("{}", cfg),
        Err(e) => eprintln!("config error: {}", e),
    }
}

Friends & Partners