Rust 程序设计语言¶
Warning
施工中!!!
第一章 入门¶
-
运行 Rust 程序
- Rust 是预编译静态类型语言
- Rust 宏
-
使用 Cargo 管理项目
- cargo build
- cargo run
- cargo check
第二章 猜数游戏¶
-
准备新项目
-
处理猜测(处理输入)
-
预导入内容与使用 use 显示引入
-
创建变量:let
-
可变变量 mut
-
不可变变量
-
-
关联函数 String::new()
或者叫静态方法
-
传入可变引用 .read_line(&mut guess)
-
Result 类型
处理潜在错误
-
占位符打印值
使用 {} 格式化字符串
-
-
生成秘密数字
随机数
- 使用 crate 增加功能
- Cargo.toml 文件与依赖管理
- 不用镜像源的话,下载很慢
- 生成随机数
- 范围表达式 .gen_range(1..=100)
-
生成本地依赖的文档
- cargo doc --open
-
比较数字
-
match 表达式
-
变量的隐藏 Shadowing > 需要转换值类型之类的场景
-
-
guess.trim().parse()
- trim() 方法会去除字符串开头和结尾的空白字符。
- parse() 将字符串转换成其他类型,需要知道具体类型。
-
使用循环
- loop 关键字创建循环
- parse() 返回 Result 类型可使用 match 处理
第三章 常见编程概念¶
- 关键字
- 变量和可变性
- 常量 const
- 隐藏 Shadowing
- 隐藏与将变量标记为 mut 是有区别的。当不小心尝试对变量重新赋值时,如果没有使用 let 关键字,就会导致编译时错误。通过使用 let,我们可以用这个值进行一些计算,不过计算完之后变量仍然是不可变的。
- mut 不能改变变量的类型
- 数据类型
- 标量 scalar
- 整型
- 有符号与无符号整型
- 数字字面值
- 整型溢出
- 浮点数
- 单精度与双精度
- 数值计算
- 布尔型
- 字符类型
- 整型
- 复合 compound
- 元组
- 元组的长度是固定的,元素的类型可以不同
- 元组的绑定
- 元组的解构
- 模式匹配
- 元组的访问
- 点号 ( . ) 后跟值的索引
- 索引从 0 开始
- 单元元组
- 表式空值或空返回类型
- 数组
- 数组的长度是固定的,元素的类型相同
- let a: [i32; 5] = [1, 2, 3, 4, 5];
- let a = [3; 5];
- 相当于 let a = [3, 3, 3, 3, 3];
- 数组的访问 a[0]
- 数组的越界访问 panic
- 数组的长度是固定的,元素的类型相同
- 元组
- 标量 scalar
- 函数
- Rust 代码中的函数和变量名使用 snake case 规范风格。在 snake case 中,所有字母都是小写并使用下划线分隔单词。
- Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行
- 参数
- 在函数签名中,必须声明每个参数的类型。
- 语句和表达式
- 因为 Rust 是一门基于表达式(expression-based)的语言
- 语句(Statements)是执行一些操作但不返回值的指令。
- let 、fn 等定义是语句
- Rust 中不能写 x = y = 6 这样的式子
- 表达式(Expressions)计算并产生一个值。
- 如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。
- 具有返回值的函数
- 函数可以向调用它的代码返回值。我们不对返回值命名,但要在箭头 ( -> )后声明它的类型
- 注释
- 控制流
- if 表达式
- 代码中的条件必须是 bool 值,Rust 并不会尝试自动地将非布尔值转换为布尔值。
- if 是表达式,所以可以在 let 语句的右侧使用
- 代码块的值是其最后一个表达式的值,而数字本身就是一个表达式
- if 的每个分支的可能的返回值都必须是相同类型
- 使用循环重复执行
- loop 无限循环
- 从循环返回值 break 表达式
- 循环标签:在嵌套循环时指定退出的循环
- while 条件循环
- for 遍历集合
- for number in (1..4).rev() {}
- rev() 用于反转一个 range
- for number in (1..4).rev() {}
- loop 无限循环
- if 表达式
第四章 认识所有权¶
-
什么是所有权
-
栈与堆
-
所有权规则
- Rust 中的每一个值都有一个所有者(owner)。
- 值在任一时刻有且只有一个所有者。
- 当所有者(变量)离开作用域,这个值将被丢弃。
-
变量作用域
-
String 类型
- ( :: ) 运算符
- 通过 String::from("hello") 创建 String
-
内存与分配
-
在 Rust 中,内存在拥有它的变量离开作用域后就被自动释放,通过调用- 一个特殊的函数 drop() 类似于 c++ 中的 RAII 概念
-
变量与数据交互的方式
-
移动
- 为了避免二次释放,Rust 认为 s1=s2 后,s1 无效,相当进行了移动。
有点像 c++ 的移动语义
-
克隆
-
拷贝
- 实现了 Copy trait 的类型在赋值后依然是可用的,以下类型实现了 Copy
- 整数类型
- 布尔类型
- 浮点数
- 字符类型
- 元组,当且仅当其包含的类型也都实现了 Copy
- (1, 2, 3, (4, 5)) 也是实现 copy 了的
- 实现了 Copy trait 的类型在赋值后依然是可用的,以下类型实现了 Copy
-
-
-
所有权与函数
-
将值传递给函数与给变量赋值的原理相似。向函数传递值可能会移动或者复制,就像赋值语句一样。
好神奇,C++ 里是实参与形参,中间是拷贝函数。而 rust 直接给移动掉了?!
-
未实现 Copy 的变量会无效,但实现了 Copy 的变量依然能使用。
-
返回值也可以转移所有权。
这就比 C++ 方便多了
-
使用元组返回值以重新获取所有权,但是依然不够方便
-
-
-
引用与借用
- 以一个对象的引用作为参数而不是获取值的所有权
- 创建一个引用的行为称为借用(borrowing)
-
可变引用 &mut
- 数据竞争问题
- 不能拥有多个可变引用
- 不能在拥有不可变引用的同时拥有可变引用
- 一个引用的作用域从声明的地方开始一直持续到最后一次使用为止
-
悬垂引用
- 不存在的
-
Slice 类型
- as_bytes() 方法将 String 转化为字节数组
- iter() 方法在字节数组上创建一个迭代器
- enumerate() 包装迭代的结果为元组
-
字符串 slice
- 是 String 中一部分值的引用
- &s[0..5] 是左闭右开
- 如果想要从索引 0 开始,可以不写两个点号之前的值
- 如果 slice 包含 String 的最后一个字节,也可以舍弃尾部的数字
- “字符串 slice” 的类型声明写作 &str
- 当拥有某值的不可变引用时,就不能再获取一个可变引用,因此试图清空原字符串的行为会报错
- 字符串字面值就是 slice
- 字符串 slice 作为参数
- 如果有一个字符串 slice,可以直接传递它。如果有一个 String,则可以传递整个 String 的 slice 或对 String 的引用
-
其他类型的 slice
第五章 使用结构体组织相关联的数据¶
- 结构体的定义和实例化
- 定义结构体,需要使用 struct 关键字
- 为了从结构体中获取某个特定的值,可以使用点号
- 使用字段初始化简写语法
- 使用结构体更新语法从其他实例创建实例
- .. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值
- let user2 = User { email: String::from("another@example.com"),..user1};
- .. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值
- 使用没有命名字段的元组结构体来创建不同的类型