本章目标

通过本章学习,你将掌握: - Rust所有权系统的核心概念 - 所有权规则和内存管理 - 借用和引用机制 - 可变引用和不可变引用 - 切片类型的使用 - 生命周期的基本概念

4.1 所有权概念

什么是所有权?

所有权是Rust最独特的特性,它使Rust能够在不使用垃圾回收器的情况下保证内存安全。

所有权规则

  1. 每个值都有一个所有者(owner)
  2. 同一时间只能有一个所有者
  3. 当所有者离开作用域时,值会被丢弃
fn main() {
    println!("🔐 所有权基础概念");
    println!("==================");
    
    // 规则1: 每个值都有一个所有者
    let s1 = String::from("hello");  // s1是字符串的所有者
    println!("s1: {}", s1);
    
    // 规则2: 同一时间只能有一个所有者
    let s2 = s1;  // 所有权从s1转移到s2
    println!("s2: {}", s2);
    // println!("s1: {}", s1);  // 错误!s1不再有效
    
    // 规则3: 当所有者离开作用域时,值会被丢弃
    {
        let s3 = String::from("world");  // s3进入作用域
        println!("s3: {}", s3);
    }  // s3离开作用域,内存被释放
    
    // println!("s3: {}", s3);  // 错误!s3已经不存在
    
    println!("程序结束,s2的内存将被释放");
}
rustc ownership_basic.rs && ./ownership_basic

移动(Move)语义

fn main() {
    println!("📦 移动语义示例");
    println!("===============");
    
    // 字符串移动
    let s1 = String::from("hello");
    let s2 = s1;  // s1的值移动到s2
    
    println!("s2: {}", s2);
    // println!("s1: {}", s1);  // 编译错误!
    
    // 函数调用中的移动
    let s3 = String::from("world");
    take_ownership(s3);  // s3的值移动到函数中
    // println!("s3: {}", s3);  // 编译错误!
    
    // 函数返回值的移动
    let s4 = give_ownership();  // 函数返回值移动到s4
    println!("s4: {}", s4);
    
    let s5 = String::from("rust");
    let s6 = take_and_give_back(s5);  // s5移动到函数,返回值移动到s6
    println!("s6: {}", s6);
    // println!("s5: {}", s5);  // 编译错误!
}

fn take_ownership(some_string: String) {
    println!("函数接收: {}", some_string);
}  // some_string离开作用域,内存被释放

fn give_ownership() -> String {
    let some_string = String::from("给你");
    some_string  // 返回值移动给调用者
}

fn take_and_give_back(a_string: String) -> String {
    a_string  // 直接返回参数
}
rustc move_semantics.rs && ./move_semantics

复制(Copy)语义

fn main() {
    println!("📋 复制语义示例");
    println!("===============");
    
    // 基本类型实现了Copy trait
    let x = 5;
    let y = x;  // x被复制到y,x仍然有效
    
    println!("x: {}, y: {}", x, y);  // 都可以使用
    
    // 函数调用中的复制
    let a = 10;
    make_copy(a);  // a被复制到函数中
    println!("a仍然有效: {}", a);  // a仍然可以使用
    
    // 元组的复制(如果所有元素都实现Copy)
    let tup1 = (1, 2, 3);
    let tup2 = tup1;  // 复制
    println!("tup1: {:?}, tup2: {:?}", tup1, tup2);
    
    // 数组的复制(如果元素实现Copy且长度已知)
    let arr1 = [1, 2, 3, 4, 5];
    let arr2 = arr1;  // 复制
    println!("arr1: {:?}, arr2: {:?}", arr1, arr2);
    
    // 实现Copy的类型
    demonstrate_copy_types();
}

fn make_copy(some_integer: i32) {
    println!("函数接收的复制: {}", some_integer);
}

fn demonstrate_copy_types() {
    println!("\n实现Copy trait的类型:");
    
    // 所有整数类型
    let i: i32 = 1;
    let j = i;
    println!("整数: i={}, j={}", i, j);
    
    // 所有浮点类型
    let f1: f64 = 3.14;
    let f2 = f1;
    println!("浮点: f1={}, f2={}", f1, f2);
    
    // 布尔类型
    let b1 = true;
    let b2 = b1;
    println!("布尔: b1={}, b2={}", b1, b2);
    
    // 字符类型
    let c1 = 'a';
    let c2 = c1;
    println!("字符: c1={}, c2={}", c1, c2);
    
    // 不可变引用
    let s = String::from("hello");
    let r1 = &s;
    let r2 = r1;  // 引用被复制
    println!("引用: r1={}, r2={}", r1, r2);
}
rustc copy_semantics.rs && ./copy_semantics

克隆(Clone)

fn main() {
    println!("🔄 克隆示例");
    println!("============");
    
    // 深拷贝字符串
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 显式克隆
    
    println!("s1: {}, s2: {}", s1, s2);  // 两个都可以使用
    
    // 克隆向量
    let vec1 = vec![1, 2, 3, 4, 5];
    let vec2 = vec1.clone();
    
    println!("vec1: {:?}", vec1);
    println!("vec2: {:?}", vec2);
    
    // 克隆复杂数据结构
    let data1 = vec![String::from("a"), String::from("b")];
    let data2 = data1.clone();
    
    println!("data1: {:?}", data1);
    println!("data2: {:?}", data2);
    
    // 克隆的性能考虑
    demonstrate_clone_cost();
}

fn demonstrate_clone_cost() {
    println!("\n克隆的性能考虑:");
    
    // 小数据的克隆
    let small_vec = vec![1, 2, 3];
    let cloned_small = small_vec.clone();
    println!("小向量克隆: {:?} -> {:?}", small_vec, cloned_small);
    
    // 大数据的克隆(注意性能)
    let large_vec: Vec<i32> = (0..1000).collect();
    println!("大向量长度: {}", large_vec.len());
    
    // 克隆大数据时要谨慎
    let cloned_large = large_vec.clone();
    println!("克隆后长度: {}", cloned_large.len());
    
    println!("提示: 克隆大数据结构可能很昂贵,考虑使用引用");
}
rustc clone_example.rs && ./clone_example

4.2 借用和引用

不可变引用

fn main() {
    println!("📖 不可变引用示例");
    println!("==================");
    
    let s1 = String::from("hello");
    
    // 创建引用
    let len = calculate_length(&s1);  // &s1创建对s1的引用
    
    println!("字符串 '{}' 的长度是 {}", s1, len);  // s1仍然有效
    
    // 多个不可变引用
    let r1 = &s1;
    let r2 = &s1;
    let r3 = &s1;
    
    println!("r1: {}, r2: {}, r3: {}", r1, r2, r3);
    
    // 引用的引用
    let r4 = &r1;
    println!("引用的引用: {}", r4);
    
    // 不同类型的引用
    let number = 42;
    let number_ref = &number;
    println!("数字引用: {}", number_ref);
    
    let arr = [1, 2, 3, 4, 5];
    let arr_ref = &arr;
    println!("数组引用: {:?}", arr_ref);
    
    // 引用作为函数参数
    print_string(&s1);
    print_length(&s1);
}

// 函数接收引用,不获取所有权
fn calculate_length(s: &String) -> usize {
    s.len()
}  // s离开作用域,但因为它是引用,所以不会释放内存

fn print_string(s: &String) {
    println!("打印字符串: {}", s);
}

fn print_length(s: &String) {
    println!("字符串长度: {}", s.len());
}
rustc immutable_references.rs && ./immutable_references

可变引用

fn main() {
    println!("✏️ 可变引用示例");
    println!("=================");
    
    let mut s = String::from("hello");
    
    // 创建可变引用
    change(&mut s);
    println!("修改后: {}", s);
    
    // 可变引用的限制:同一时间只能有一个
    let r1 = &mut s;
    // let r2 = &mut s;  // 错误!不能同时有两个可变引用
    
    println!("可变引用: {}", r1);
    
    // 可变引用和不可变引用不能同时存在
    let mut s2 = String::from("world");
    
    {
        let r1 = &s2;      // 不可变引用
        let r2 = &s2;      // 另一个不可变引用
        println!("不可变引用: {}, {}", r1, r2);
        // r1和r2在这里结束使用
    }
    
    let r3 = &mut s2;   // 现在可以创建可变引用
    println!("可变引用: {}", r3);
    
    // 引用的作用域
    demonstrate_reference_scope();
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

fn demonstrate_reference_scope() {
    println!("\n引用作用域示例:");
    
    let mut s = String::from("hello");
    
    let r1 = &s;        // 不可变引用开始
    let r2 = &s;        // 另一个不可变引用
    println!("不可变引用: {}, {}", r1, r2);
    // r1和r2的作用域在这里结束(最后一次使用)
    
    let r3 = &mut s;    // 可变引用开始
    r3.push_str(", rust");
    println!("可变引用: {}", r3);
    // r3的作用域在这里结束
    
    // 现在又可以创建新的引用了
    let r4 = &s;
    println!("新的不可变引用: {}", r4);
}
rustc mutable_references.rs && ./mutable_references

悬垂引用(Dangling References)

fn main() {
    println!("⚠️ 悬垂引用示例");
    println!("=================");
    
    // Rust编译器防止悬垂引用
    // let reference_to_nothing = dangle();  // 这会编译错误!
    
    // 正确的做法:返回值而不是引用
    let s = no_dangle();
    println!("正确返回的字符串: {}", s);
    
    // 演示作用域和生命周期
    demonstrate_lifetimes();
}

// 这个函数会导致悬垂引用(编译错误)
/*
fn dangle() -> &String {  // 返回字符串的引用
    let s = String::from("hello");  // s是新字符串
    &s  // 返回字符串s的引用
}  // s离开作用域并被丢弃,其内存被释放
   // 引用指向的内存已经无效!
*/

// 正确的做法:返回String本身
fn no_dangle() -> String {
    let s = String::from("hello");
    s  // 返回String,所有权转移给调用者
}

fn demonstrate_lifetimes() {
    println!("\n生命周期演示:");
    
    let string1 = String::from("long string is long");
    
    {
        let string2 = String::from("xyz");
        let result = longest(&string1, &string2);
        println!("最长的字符串: {}", result);
    }  // string2在这里离开作用域
    
    // 如果我们试图在string2离开作用域后使用result,会出错
    // println!("结果: {}", result);  // 编译错误!
}

// 这个函数需要生命周期参数(在后续章节详细讲解)
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
rustc dangling_references.rs && ./dangling_references

4.3 切片类型

字符串切片

fn main() {
    println!("🔪 字符串切片示例");
    println!("==================");
    
    let s = String::from("hello world");
    
    // 创建字符串切片
    let hello = &s[0..5];   // 或 &s[..5]
    let world = &s[6..11];  // 或 &s[6..]
    let whole = &s[..];     // 整个字符串的切片
    
    println!("原字符串: {}", s);
    println!("hello: {}", hello);
    println!("world: {}", world);
    println!("whole: {}", whole);
    
    // 字符串字面量就是切片
    let literal = "Hello, world!";  // 类型是 &str
    println!("字符串字面量: {}", literal);
    
    // 使用切片的函数
    let word = first_word(&s);
    println!("第一个单词: {}", word);
    
    let word2 = first_word("hello rust");
    println!("第一个单词: {}", word2);
    
    // 切片的安全性
    demonstrate_slice_safety();
    
    // 中文字符串切片(注意字节边界)
    demonstrate_unicode_slices();
}

// 返回第一个单词的切片
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    
    &s[..]  // 如果没有空格,返回整个字符串
}

fn demonstrate_slice_safety() {
    println!("\n切片安全性演示:");
    
    let mut s = String::from("hello world");
    let word = first_word(&s);
    
    println!("第一个单词: {}", word);
    
    // 如果我们试图修改s,编译器会阻止
    // s.clear();  // 错误!不能在有不可变引用时修改
    
    // 正确的做法:在使用完切片后再修改
    // 这里word的作用域结束
    
    s.clear();  // 现在可以修改了
    println!("清空后的字符串: '{}'", s);
}

fn demonstrate_unicode_slices() {
    println!("\nUnicode切片演示:");
    
    let s = String::from("你好世界");
    
    // 中文字符是3字节,所以要小心切片边界
    let hello = &s[0..6];   // "你好" (每个中文字符3字节)
    let world = &s[6..12];  // "世界"
    
    println!("中文字符串: {}", s);
    println!("你好: {}", hello);
    println!("世界: {}", world);
    
    // 更安全的方式:使用字符迭代器
    let chars: Vec<char> = s.chars().collect();
    println!("字符数组: {:?}", chars);
    
    // 按字符切片
    let char_slice: String = chars[0..2].iter().collect();
    println!("前两个字符: {}", char_slice);
}
rustc string_slices.rs && ./string_slices

数组切片

fn main() {
    println!("📊 数组切片示例");
    println!("===============");
    
    let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 创建数组切片
    let slice1 = &arr[1..4];    // [2, 3, 4]
    let slice2 = &arr[..3];     // [1, 2, 3]
    let slice3 = &arr[7..];     // [8, 9, 10]
    let slice4 = &arr[..];      // 整个数组
    
    println!("原数组: {:?}", arr);
    println!("slice1 [1..4]: {:?}", slice1);
    println!("slice2 [..3]: {:?}", slice2);
    println!("slice3 [7..]: {:?}", slice3);
    println!("slice4 [..]: {:?}", slice4);
    
    // 切片的长度和索引
    println!("\n切片信息:");
    println!("slice1长度: {}", slice1.len());
    println!("slice1第一个元素: {}", slice1[0]);
    
    // 遍历切片
    println!("\n遍历slice1:");
    for (i, &value) in slice1.iter().enumerate() {
        println!("索引{}: {}", i, value);
    }
    
    // 切片作为函数参数
    let sum = sum_slice(slice1);
    println!("slice1的和: {}", sum);
    
    let max = find_max(&arr[5..8]);
    println!("arr[5..8]的最大值: {}", max);
    
    // 可变切片
    demonstrate_mutable_slices();
}

fn sum_slice(slice: &[i32]) -> i32 {
    let mut sum = 0;
    for &value in slice {
        sum += value;
    }
    sum
}

fn find_max(slice: &[i32]) -> i32 {
    let mut max = slice[0];
    for &value in slice {
        if value > max {
            max = value;
        }
    }
    max
}

fn demonstrate_mutable_slices() {
    println!("\n可变切片演示:");
    
    let mut arr = [1, 2, 3, 4, 5];
    println!("原数组: {:?}", arr);
    
    // 创建可变切片
    let slice = &mut arr[1..4];
    println!("可变切片: {:?}", slice);
    
    // 修改切片中的元素
    slice[0] = 10;
    slice[1] = 20;
    slice[2] = 30;
    
    println!("修改后的切片: {:?}", slice);
    println!("修改后的数组: {:?}", arr);
    
    // 使用函数修改切片
    double_slice(&mut arr[..]);
    println!("翻倍后的数组: {:?}", arr);
}

fn double_slice(slice: &mut [i32]) {
    for value in slice {
        *value *= 2;
    }
}
rustc array_slices.rs && ./array_slices

4.4 所有权模式

函数中的所有权

fn main() {
    println!("🔄 所有权模式示例");
    println!("==================");
    
    // 模式1: 传递所有权
    let s1 = String::from("hello");
    let s2 = take_ownership_pattern(s1);
    // s1不再有效,s2现在拥有值
    println!("返回的字符串: {}", s2);
    
    // 模式2: 借用(不可变引用)
    let s3 = String::from("world");
    let len = borrow_pattern(&s3);
    println!("字符串 '{}' 长度: {}", s3, len);  // s3仍然有效
    
    // 模式3: 可变借用
    let mut s4 = String::from("rust");
    modify_pattern(&mut s4);
    println!("修改后: {}", s4);
    
    // 模式4: 返回多个值
    let s5 = String::from("programming");
    let (s6, len) = calculate_length_pattern(s5);
    println!("字符串 '{}' 长度: {}", s6, len);
    
    // 复杂的所有权转移
    demonstrate_complex_ownership();
}

// 模式1: 获取所有权并返回
fn take_ownership_pattern(s: String) -> String {
    println!("函数接收: {}", s);
    s  // 返回所有权
}

// 模式2: 借用,不获取所有权
fn borrow_pattern(s: &String) -> usize {
    s.len()
}

// 模式3: 可变借用
fn modify_pattern(s: &mut String) {
    s.push_str(" is awesome!");
}

// 模式4: 获取所有权,返回所有权和其他值
fn calculate_length_pattern(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)
}

fn demonstrate_complex_ownership() {
    println!("\n复杂所有权转移:");
    
    let mut vec = vec![String::from("a"), String::from("b"), String::from("c")];
    println!("原向量: {:?}", vec);
    
    // 从向量中取出元素(移动所有权)
    let first = vec.remove(0);
    println!("取出的元素: {}", first);
    println!("剩余向量: {:?}", vec);
    
    // 添加元素
    vec.push(String::from("d"));
    println!("添加后: {:?}", vec);
    
    // 交换元素
    vec.swap(0, 1);
    println!("交换后: {:?}", vec);
    
    // 使用迭代器(借用)
    for (i, item) in vec.iter().enumerate() {
        println!("索引{}: {}", i, item);
    }
    
    // 向量仍然有效
    println!("向量仍然存在: {:?}", vec);
}
rustc ownership_patterns.rs && ./ownership_patterns

结构体中的所有权

// 拥有数据的结构体
struct User {
    username: String,    // 拥有String
    email: String,       // 拥有String
    sign_in_count: u64,  // Copy类型
    active: bool,        // Copy类型
}

// 使用引用的结构体(需要生命周期参数)
struct UserRef<'a> {
    username: &'a str,   // 借用str
    email: &'a str,      // 借用str
    sign_in_count: u64,
    active: bool,
}

fn main() {
    println!("🏗️ 结构体所有权示例");
    println!("====================");
    
    // 创建拥有数据的结构体
    let user1 = User {
        username: String::from("alice"),
        email: String::from("alice@example.com"),
        sign_in_count: 1,
        active: true,
    };
    
    println!("用户1: {} ({})", user1.username, user1.email);
    
    // 部分移动
    let username = user1.username;  // 移动username
    let email = user1.email;        // 移动email
    
    // user1.username 和 user1.email 不再有效
    // 但 user1.sign_in_count 和 user1.active 仍然有效(Copy类型)
    println!("登录次数: {}", user1.sign_in_count);
    println!("是否活跃: {}", user1.active);
    
    // println!("用户名: {}", user1.username);  // 错误!已移动
    
    // 使用移动的值
    println!("移动的用户名: {}", username);
    println!("移动的邮箱: {}", email);
    
    // 创建新用户
    let user2 = User {
        username: String::from("bob"),
        email: String::from("bob@example.com"),
        sign_in_count: 0,
        active: false,
    };
    
    // 使用引用访问结构体字段
    print_user_info(&user2);
    
    // user2仍然有效
    println!("user2仍然有效: {}", user2.username);
    
    // 结构体更新语法
    let user3 = User {
        username: String::from("charlie"),
        email: String::from("charlie@example.com"),
        ..user2  // 复制其他字段(这里会移动user2的String字段)
    };
    
    println!("用户3: {} ({})", user3.username, user3.email);
    // user2的String字段已被移动,但Copy字段仍可用
    println!("user2的登录次数: {}", user2.sign_in_count);
    
    // 使用引用的结构体
    demonstrate_reference_struct();
}

fn print_user_info(user: &User) {
    println!("用户信息: {} ({}), 登录{}次, 活跃: {}", 
             user.username, user.email, user.sign_in_count, user.active);
}

fn demonstrate_reference_struct() {
    println!("\n引用结构体演示:");
    
    let username = "david";
    let email = "david@example.com";
    
    let user_ref = UserRef {
        username,
        email,
        sign_in_count: 5,
        active: true,
    };
    
    println!("引用用户: {} ({})", user_ref.username, user_ref.email);
    
    // 原始数据仍然有效
    println!("原始用户名: {}", username);
    println!("原始邮箱: {}", email);
}
rustc struct_ownership.rs && ./struct_ownership

4.5 常见所有权问题和解决方案

问题1:使用值后再次使用

fn main() {
    println!("🔧 常见所有权问题和解决方案");
    println!("==============================");
    
    // 问题1: 使用值后再次使用
    problem1_solution();
    
    // 问题2: 在循环中移动值
    problem2_solution();
    
    // 问题3: 返回引用到局部变量
    problem3_solution();
    
    // 问题4: 可变引用和不可变引用冲突
    problem4_solution();
}

fn problem1_solution() {
    println!("\n问题1: 使用值后再次使用");
    
    // 错误的做法(会编译失败)
    /*
    let s = String::from("hello");
    let len = calculate_length_wrong(s);  // s被移动
    println!("长度: {}", len);
    println!("字符串: {}", s);  // 错误!s已被移动
    */
    
    // 解决方案1: 使用引用
    let s = String::from("hello");
    let len = calculate_length_right(&s);  // 借用s
    println!("字符串: '{}', 长度: {}", s, len);  // s仍然有效
    
    // 解决方案2: 返回所有权
    let s2 = String::from("world");
    let (s3, len) = calculate_length_return(s2);
    println!("字符串: '{}', 长度: {}", s3, len);
    
    // 解决方案3: 克隆
    let s4 = String::from("rust");
    let len = calculate_length_wrong(s4.clone());  // 克隆s4
    println!("字符串: '{}', 长度: {}", s4, len);  // s4仍然有效
}

fn calculate_length_wrong(s: String) -> usize {
    s.len()
}

fn calculate_length_right(s: &String) -> usize {
    s.len()
}

fn calculate_length_return(s: String) -> (String, usize) {
    let len = s.len();
    (s, len)
}

fn problem2_solution() {
    println!("\n问题2: 在循环中移动值");
    
    let strings = vec![
        String::from("hello"),
        String::from("world"),
        String::from("rust"),
    ];
    
    // 错误的做法(会编译失败)
    /*
    for s in strings {
        println!("{}", s);  // s被移动到这里
    }
    println!("{:?}", strings);  // 错误!strings已被移动
    */
    
    // 解决方案1: 使用引用
    for s in &strings {
        println!("引用: {}", s);
    }
    println!("原向量仍然有效: {:?}", strings);
    
    // 解决方案2: 使用索引
    for i in 0..strings.len() {
        println!("索引访问: {}", strings[i]);
    }
    
    // 解决方案3: 使用iter()
    for s in strings.iter() {
        println!("迭代器: {}", s);
    }
    
    println!("向量仍然存在: {:?}", strings);
}

fn problem3_solution() {
    println!("\n问题3: 返回引用到局部变量");
    
    // 错误的做法(会编译失败)
    /*
    fn create_string() -> &String {
        let s = String::from("hello");
        &s  // 错误!返回对局部变量的引用
    }
    */
    
    // 解决方案1: 返回拥有的值
    let s = create_string_owned();
    println!("拥有的字符串: {}", s);
    
    // 解决方案2: 使用静态字符串
    let s = get_static_string();
    println!("静态字符串: {}", s);
    
    // 解决方案3: 接受参数并返回引用
    let mut buffer = String::new();
    let s = fill_string(&mut buffer);
    println!("填充的字符串: {}", s);
}

fn create_string_owned() -> String {
    String::from("hello")
}

fn get_static_string() -> &'static str {
    "hello, world"
}

fn fill_string(buffer: &mut String) -> &str {
    buffer.push_str("hello from buffer");
    buffer
}

fn problem4_solution() {
    println!("\n问题4: 可变引用和不可变引用冲突");
    
    let mut s = String::from("hello");
    
    // 错误的做法(会编译失败)
    /*
    let r1 = &s;        // 不可变引用
    let r2 = &s;        // 另一个不可变引用
    let r3 = &mut s;    // 错误!不能在有不可变引用时创建可变引用
    println!("{}, {}, {}", r1, r2, r3);
    */
    
    // 解决方案1: 分离作用域
    {
        let r1 = &s;
        let r2 = &s;
        println!("不可变引用: {}, {}", r1, r2);
    }  // r1和r2在这里离开作用域
    
    let r3 = &mut s;
    r3.push_str(", world");
    println!("可变引用: {}", r3);
    
    // 解决方案2: 理解引用的生命周期
    let r4 = &s;
    let r5 = &s;
    println!("不可变引用: {}, {}", r4, r5);
    // r4和r5在这里结束使用
    
    let r6 = &mut s;  // 现在可以创建可变引用
    r6.push_str("!");
    println!("最终字符串: {}", r6);
}
rustc ownership_problems.rs && ./ownership_problems

4.6 综合示例:文本处理器

use std::collections::HashMap;

/// 文本统计信息
struct TextStats {
    word_count: usize,
    char_count: usize,
    line_count: usize,
    word_frequency: HashMap<String, usize>,
}

impl TextStats {
    fn new() -> Self {
        TextStats {
            word_count: 0,
            char_count: 0,
            line_count: 0,
            word_frequency: HashMap::new(),
        }
    }
    
    fn analyze_text(&mut self, text: &str) {
        self.char_count = text.chars().count();
        self.line_count = text.lines().count();
        
        // 分析单词
        for word in text.split_whitespace() {
            let word = word.to_lowercase();
            let word = word.trim_matches(|c: char| !c.is_alphabetic());
            
            if !word.is_empty() {
                self.word_count += 1;
                *self.word_frequency.entry(word.to_string()).or_insert(0) += 1;
            }
        }
    }
    
    fn get_most_frequent_word(&self) -> Option<(&String, &usize)> {
        self.word_frequency
            .iter()
            .max_by_key(|(_, &count)| count)
    }
    
    fn print_stats(&self) {
        println!("文本统计:");
        println!("  字符数: {}", self.char_count);
        println!("  单词数: {}", self.word_count);
        println!("  行数: {}", self.line_count);
        
        if let Some((word, count)) = self.get_most_frequent_word() {
            println!("  最频繁单词: '{}' (出现{}次)", word, count);
        }
    }
}

/// 文本处理器
struct TextProcessor {
    content: String,
}

impl TextProcessor {
    fn new(content: String) -> Self {
        TextProcessor { content }
    }
    
    fn get_content(&self) -> &str {
        &self.content
    }
    
    fn append_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    
    fn replace_text(&mut self, from: &str, to: &str) {
        self.content = self.content.replace(from, to);
    }
    
    fn get_lines(&self) -> Vec<&str> {
        self.content.lines().collect()
    }
    
    fn get_words(&self) -> Vec<&str> {
        self.content.split_whitespace().collect()
    }
    
    fn find_word_positions(&self, word: &str) -> Vec<usize> {
        let mut positions = Vec::new();
        let content_lower = self.content.to_lowercase();
        let word_lower = word.to_lowercase();
        
        let mut start = 0;
        while let Some(pos) = content_lower[start..].find(&word_lower) {
            positions.push(start + pos);
            start += pos + word_lower.len();
        }
        
        positions
    }
}

fn main() {
    println!("📝 文本处理器示例");
    println!("==================");
    
    // 创建文本处理器
    let sample_text = String::from(
        "Rust is a systems programming language. \
         Rust is fast and memory-safe. \
         Rust prevents segfaults and guarantees thread safety. \
         Many companies use Rust for performance-critical applications."
    );
    
    let mut processor = TextProcessor::new(sample_text);
    
    println!("原始文本:");
    println!("{}", processor.get_content());
    println!();
    
    // 分析文本
    let mut stats = TextStats::new();
    stats.analyze_text(processor.get_content());
    stats.print_stats();
    println!();
    
    // 获取行和单词
    let lines = processor.get_lines();
    println!("文本行数: {}", lines.len());
    for (i, line) in lines.iter().enumerate() {
        println!("第{}行: {}", i + 1, line);
    }
    println!();
    
    let words = processor.get_words();
    println!("前10个单词: {:?}", &words[..10.min(words.len())]);
    println!();
    
    // 查找单词位置
    let positions = processor.find_word_positions("Rust");
    println!("'Rust'出现的位置: {:?}", positions);
    
    // 修改文本
    processor.replace_text("Rust", "The Rust language");
    println!("\n替换后的文本:");
    println!("{}", processor.get_content());
    
    // 添加文本
    processor.append_text(" Rust is amazing!");
    println!("\n添加文本后:");
    println!("{}", processor.get_content());
    
    // 重新分析
    let mut new_stats = TextStats::new();
    new_stats.analyze_text(processor.get_content());
    println!();
    new_stats.print_stats();
    
    // 演示所有权转移
    demonstrate_ownership_transfer(processor);
}

fn demonstrate_ownership_transfer(processor: TextProcessor) {
    println!("\n所有权转移演示:");
    println!("处理器内容长度: {}", processor.get_content().len());
    
    // processor的所有权已转移到这个函数
    // 当函数结束时,processor会被丢弃
    
    println!("函数结束,处理器将被丢弃");
}

// 辅助函数:创建文本摘要
fn create_summary(text: &str, max_words: usize) -> String {
    let words: Vec<&str> = text.split_whitespace().take(max_words).collect();
    words.join(" ") + "..."
}

// 辅助函数:计算文本相似度(简单版本)
fn calculate_similarity(text1: &str, text2: &str) -> f64 {
    let words1: std::collections::HashSet<&str> = text1.split_whitespace().collect();
    let words2: std::collections::HashSet<&str> = text2.split_whitespace().collect();
    
    let intersection = words1.intersection(&words2).count();
    let union = words1.union(&words2).count();
    
    if union == 0 {
        0.0
    } else {
        intersection as f64 / union as f64
    }
}
rustc text_processor.rs && ./text_processor

本章小结

通过本章学习,你应该掌握了:

所有权规则: 每个值有一个所有者,同时只能有一个所有者,所有者离开作用域时值被丢弃 ✅ 移动语义: 值的所有权如何在赋值和函数调用中转移 ✅ 借用机制: 使用引用访问值而不获取所有权 ✅ 引用规则: 不可变引用可以有多个,可变引用同时只能有一个 ✅ 切片类型: 对数组或字符串部分的引用 ✅ 内存安全: Rust如何在编译时防止内存错误

下一章预告

在下一章《数据结构》中,我们将学习:

  • 结构体的定义和使用
  • 枚举类型和模式匹配
  • 方法和关联函数
  • 结构体的所有权模式
  • 复杂数据结构的设计

练习题

练习1:字符串操作

编写函数实现字符串的各种操作,注意所有权的处理: - 字符串连接 - 字符串分割 - 字符串查找和替换

练习2:向量管理

创建一个向量管理器,实现添加、删除、查找元素的功能,正确处理所有权。

练习3:引用计数

实现一个简单的引用计数系统,跟踪值被引用的次数。

练习4:文件路径处理

编写函数处理文件路径,包括路径连接、文件名提取、扩展名处理等。


恭喜你掌握了Rust的所有权系统! 🎉

所有权是Rust最重要的概念,理解它是掌握Rust的关键。现在让我们继续学习如何使用结构体和枚举来组织数据!