第10篇:归属权与借用——Rust的安全保障 Rust中文编程

第10篇:归属权与借用------Rust的安全保障

作者: 李金雨
联系方式: wbtm2718@qq.com
目标读者: Rust中文编程
核心理念: AI时代必须使用中文编程,母语编程阅读效率极高


1. 开篇引入

本课目标

  • 理解什么是归属权(所有权)
  • 理解Rust所有权的规则
  • 掌握借用的概念和使用方法
  • 理解借用的规则
  • 掌握切片的使用

生活场景引入

想象一下,你有一本漫画书,你是这本书的所有者。当你把这本书借给朋友时,朋友暂时拥有这本书的使用权,但所有权还是你的。朋友看完后,需要把书还给你,你才能继续使用它。

在Rust中,数据也有所有权,就像漫画书一样。当你把数据传递给其他变量或函数时,所有权会转移,就像把书借给朋友一样。

预期成果展示

通过这节课的学习,你将能够:

  • 理解Rust的所有权系统
  • 正确使用所有权转移
  • 掌握借用的方法
  • 理解借用的规则
  • 正确使用切片

2. 概念讲解

什么是归属权(所有权)

归属权(所有权)是Rust中一个特殊的概念,它决定了谁拥有数据,以及数据何时被释放。

所有权的规则

  1. 每个值都有一个所有者:每个值在Rust中都有一个变量作为它的所有者
  2. 同一时间只能有一个所有者:一个值不能有多个所有者
  3. 所有者离开作用域,值被丢弃:当所有者离开作用域时,值会被自动释放

归属权转移

当你把一个值赋给另一个变量时,所有权会转移:

rust 复制代码
fn main() {
    let 字符串一 = String::from("你好"); // 字符串一拥有"你好"的所有权
    let 字符串二 = 字符串一; // 所有权转移给字符串二
    
    // println!("{}", 字符串一); // 错误:字符串一已经失去所有权
    println!("{}", 字符串二); // 正确:字符串二拥有所有权
}

借用

借用是指临时使用他人的数据,而不获取所有权。就像借书一样,你可以暂时使用,但书的所有权还是别人的。

不可变借用

不可变借用使用&符号,表示临时读取数据:

rust 复制代码
fn main() {
    fn 打印长度(字符串: &String) {
        println!("长度:{}", 字符串.len());
    }

    let 字符串 = String::from("你好");
    打印长度(&字符串); // 不可变借用
    println!("{}", 字符串); // 仍然可以使用,因为没有转移所有权
}
可变借用

可变借用使用&mut符号,表示临时修改数据:

rust 复制代码
fn 修改字符串(字符串: &mut String) {
    字符串.push_str(", 世界!");
}

fn main() {
    let mut 字符串 = String::from("你好");
    修改字符串(&mut 字符串); // 可变借用
    println!("{}", 字符串); // 输出:你好, 世界!
}

借用规则

  1. 同一时间只能有一个可变借用:一个数据不能同时被多个可变借用
  2. 可变借用和不可变借用不能同时存在:如果有可变借用,就不能有不可变借用
  3. 借用的生命周期不能超过所有者的生命周期:借用不能比所有者存在更久
rust 复制代码
fn main() {
    let mut 字符串 = String::from("你好");
    
    let 借用一 = &字符串; // 不可变借用
    // let 借用二 = &mut 字符串; // 错误:不能同时有不可变借用和可变借用
    
    println!("{}", 借用一);
    
    let 借用二 = &mut 字符串; // 正确:不可变借用已经使用完毕
    借用二.push_str(", 世界!");
    println!("{}", 借用二);
}

切片

切片是对数据的一部分的引用,它没有所有权。

字符串切片

字符串切片是对字符串的一部分的引用:

rust 复制代码
fn main() {
    let 字符串 = String::from("你好,世界!");
    let 切片 = &字符串[0..3]; // 从索引0到2的字符(不包括3)
    println!("切片:{}", 切片); // 输出:你好,
    
    let 整个切片 = &字符串[..]; // 整个字符串的切片
    println!("整个切片:{}", 整个切片); // 输出:你好,世界!
}
数组切片

数组切片是对数组的一部分的引用:

rust 复制代码
fn main() {
    let 数组 = [1, 2, 3, 4, 5];
    let 切片 = &数组[1..4]; // 从索引1到3的元素(不包括4)
    println!("切片:{:?}", 切片); // 输出:[2, 3, 4]
    
    let 整个切片 = &数组[..]; // 整个数组的切片
    println!("整个切片:{:?}", 整个切片); // 输出:[1, 2, 3, 4, 5]
}

3. 动手实践

基础练习(必做)

  1. 归属权转移练习

    rust 复制代码
    fn main() {
        let 字符串一 = String::from("你好");
        println!("字符串一:{}", 字符串一);
        
        let 字符串二 = 字符串一;
        // println!("字符串一:{}", 字符串一); // 错误:字符串一已经失去所有权
        println!("字符串二:{}", 字符串二);
    }
  2. 不可变借用练习

    rust 复制代码
    fn main() {
        fn 打印内容(字符串: &String) {
            println!("内容:{}", 字符串);
        }
    
        let 字符串 = String::from("你好,世界!");
        打印内容(&字符串);
        println!("原字符串:{}", 字符串); // 仍然可以使用
    }
  3. 可变借用练习

    rust 复制代码
    fn main() {
        fn 追加内容(字符串: &mut String, 内容: &str) {
            字符串.push_str(内容);
        }
    
        let mut 字符串 = String::from("你好");
        追加内容(&mut 字符串, ",世界!");
        println!("修改后的字符串:{}", 字符串);
    }

进阶练习(选做)

  1. 编写函数交换两个变量的值

    rust 复制代码
    fn main() {
        fn 交换(a: &mut i32, b: &mut i32) {
            let 临时 = *a;
            *a = *b;
            *b = 临时;
        }
    
        let mut x = 1;
        let mut y = 2;
        println!("交换前:x = {}, y = {}", x, y);
        交换(&mut x, &mut y);
        println!("交换后:x = {}, y = {}", x, y);
    }
  2. 编写函数修改字符串内容

    rust 复制代码
    fn main() {
        fn 首字母大写(字符串: &mut String) {
            if let Some(第一个字符) = 字符串.chars().next() {
                let 大写 = 第一个字符.to_uppercase().to_string();
                字符串.replace_range(0..1, &大写);
            }
        }
    
        let mut 字符串 = String::from("hello");
        println!("修改前:{}", 字符串);
        首字母大写(&mut 字符串);
        println!("修改后:{}", 字符串);
    }

挑战练习(拓展)

  1. 编写函数计算向量的总和

    rust 复制代码
    fn main() {
        fn 计算总和(数字们: &Vec<i32>) -> i32 {
            let mut 总和 = 0;
            for 数字 in 数字们 {
                总和 += 数字;
            }
            总和
        }
    
        let 数字们 = vec![1, 2, 3, 4, 5];
        let 总和 = 计算总和(&数字们);
        println!("总和:{}", 总和);
        println!("原向量:{:?}", 数字们); // 仍然可以使用
    }

4. 知识总结

核心概念回顾

  • 所有权:数据的拥有者,决定了数据的生命周期
  • 所有权转移:当值被赋给另一个变量时,所有权会转移
  • 借用:临时使用他人的数据,不获取所有权
  • 不可变借用 :使用&符号,只能读取数据
  • 可变借用 :使用&mut符号,可以修改数据
  • 借用规则:同一时间只能有一个可变借用,可变借用和不可变借用不能同时存在
  • 切片:对数据一部分的引用,没有所有权

关键代码速查

概念 代码 说明
所有权转移 let b = a; 所有权从a转移到b
不可变借用 &a 创建一个不可变借用
可变借用 &mut a 创建一个可变借用
字符串切片 &s[0..3] 创建一个字符串切片
数组切片 &arr[1..4] 创建一个数组切片

常见错误提醒

  1. 使用已移动的值:尝试使用已经失去所有权的值
  2. 借用冲突:同时有多个可变借用,或者同时有可变借用和不可变借用
  3. 生命周期问题:借用的生命周期超过了所有者的生命周期
  4. 切片越界:创建的切片超出了数据的范围

5. 课后作业

巩固练习题

  1. 编写一个程序,演示所有权转移的过程
  2. 编写一个函数,使用不可变借用来计算字符串的长度
  3. 编写一个函数,使用可变借用来修改向量的内容

创意编程题

  1. 发挥你的创意,创建一个程序,使用借用和所有权来管理资源
  2. 编写一个程序,使用切片来处理字符串和数组

下篇预习提示

下一篇我们将学习"选择模板与模式匹配------处理多种可能性",这是Rust中处理多种情况的强大工具。预习一下:

  • 什么是选择模板(枚举)?
  • 如何定义枚举?
  • 什么是模式匹配?
  • 如何使用match表达式?

恭喜你完成了第十篇教程!你已经掌握了Rust的所有权系统,学会了如何安全地管理数据。继续加油,下一篇我们将学习如何处理多种可能性!

学习交流

如果你在学习过程中遇到任何问题,欢迎联系我:

  • ** 视频号,"时空系"
  • 邮箱: wbtm2718@qq.com
  • 其他提示:
  • 本人正在开发纯中文编程语言和编译器,有兴趣的可以交流
  • 本人正在写一本基于中国母语思维习惯的数学教材,可以让你一年内学完从初中到研究生的数学,而且可以让你快速掌握人工智能的关键数学知识,有兴趣的可以交流

祝你学习愉快!

相关推荐
AI进化营-智能译站1 小时前
ROS2 C++开发系列13-运算符重载让ROS2消息处理更自然
java·开发语言·c++·ai
时空系1 小时前
第6篇:数据容器——管理大量数据 Rust中文编程
开发语言·后端·rust
eLIN TECE1 小时前
Go基础之环境搭建
开发语言·后端·golang
念何架构之路1 小时前
Go反射应用技巧
开发语言·后端·golang
shjita2 小时前
java根据键值对中值的大小进行排序的手法。
java·开发语言·servlet
Chockmans2 小时前
春秋云境CVE-2017-3506
安全·web安全·网络安全·系统安全·安全威胁分析·春秋云境·cve-2017-3506
开开心心就好2 小时前
近200个工具的电脑故障修复合集
安全·智能手机·pdf·电脑·consul·memcache·1024程序员节
Rabitebla2 小时前
vector 的骨架:三根指针、模板陷阱与迭代器失效的第一现场
开发语言·数据结构·c++·算法
时空系2 小时前
第7篇:功能——打造你的工具箱 Rust中文编程
开发语言·网络·rust