Rust 学习笔记1
写在前面
我学习整个项目是通过看书和视频学习的,以及练习一些代码。
整个博客写的比较粗糙(我自己是有C/C++,Python,Java基础来看的视频,所以很多很基础的东西我就没有写。),可能后续还会更新,总而言之,可以粗略的看。
比较适合复习来看,初学的话还是建议看下面的书和视频。
书:《The Rust Programming Language》或中文版《Rust权威指南》
视频:Rust编程语言入门教程(Rust语言/Rust权威指南配套)【已完结】
本篇概要
本篇内容包含为什么要学习Rust,Rust使用初步,Rust编程初步
0 为什么要学习Rust
- 涉及内存管理、数据表示、并发的底层细节
- Rust的风险相对较低
- 不局限于底层项目
1 初步了解Rust
1.0 初始注意事项
- !调用的是Rust宏,不是普通的函数
- Rust以;作为语句的结尾
- Rust程序应该先编译再运行(预编译静态类型)
- 编译rustc filename.rs
- 运行 filename
1.1 Cargo
1.1.0 Cargo的介绍
- Rust的构建系统和包管理器
- 启用cargo将更加容易添加项目依赖项
1.1.1 使用Cargo构建项目
cargo new project_name
- 生成一个带有cargo.toml和.gitignore文件的项目
- 在已有项目中使用cargo new不会覆盖.gitignore文件,可以运行
cargo new —vcs=git来覆盖这些行为
1.1.2 Cargo.toml
-
使用了TOML格式
-
第一行[package]是一个片段标题
下面三行配置了Cargo编译所需的项目配置:项目的名称、项目的版本
以及要使用的Rust版本
-
最后一行[dependencies]罗列项目依赖的片段
-
Cargo 期望源文件存放在 src 目录中。项目根目录只存放 README、license 信息、配置文件和其他跟代码无关的文件。使用 Cargo 帮助你保持项目干净整洁,一切井井有条。
1.1.3 构建和运行Cargo项目
cargo build
可以在target/debug下产生编译后的可运行文件
cargo run
直接编译并执行可执行文件
cargo check
可以快速检查代码并保证其可以编译,但是不编译
- 养成定期运行cargo check的习惯,确保项目可以被编译
cargo build —release
会在target/release下产生可执行文件
1.2 Rust编程初步
1.2.1 Rust库
-
Rust会提前导入一些库进入程序中,叫做预导入
-
没有导入的库需要自己手动导入 use std::io
use将std::io显式地导入了
1.2.2 Rust变量
- 使用let创建变量
- 在Rust中变量默认是不可以变的,一旦给变量赋值,值就不可以修改
1.2.3 引入外部库
修改Cargo.toml中的dependencies来引入外部库
1.2.4 Cargo.lock
保证项目的版本控制
1.2.5 match表达式
一个match表达式应该包含一个模式
1.2.6 隐藏变量
把string类型变成int还可以用同样的名字进行声明
2 Rust编程基础
- Rust同其他语言一样,也有保留的关键字库
2.1 变量及其可变性
2.1.1 变量
- 变量默认不可以改变其值
- 如果需要声明可以修改的变量,需要在let后面加上mut关键字
- 不可变性可以帮助我们更好的去推导我们的代码
2.1.2 常量
- 常量使用const进行声明
- 常量必须写清楚数据类型
- 常量只能被设置成为常量表达式
const THREE_HOURS_IN_SECONDS : u32= 60 * 60 * 3 ;
- Rust对常量的命名规约是:单词之间使用下划线,单词全大写
2.1.3 隐藏
-
当定义一个与第一个变量名字相同的第二个变量的时候,第二个变量就隐藏了第一个变量
-
可以使用let进行多次隐藏,每一次隐藏的作用域结束,隐藏结束
-
隐藏 vs. mut
隐藏其实是创建了一个新的同名变量
mut还是原来的变量
2.2 数据类型
- Rust是静态类型语言,必须知道变量的类型才可以编译
2.2.1 标量类型
-
整型
有符号是i开头,无符号是u开头
长度为多少bit,字母就加多少
特殊的arch类型,标记为isize,usize:依赖的是计算机的架构,计算机是多少位架构,它就是多少位
整型溢出
当值超过可以表达的范围的时候,会发生这种现象
使用—realese时候不会检查溢出,只会循环
-
浮点型
rust的浮点数为f32与f64两种,后者为默认
-
布尔类型
可能的值:true false
-
字符类型 char
使用’c’声明char字面量
使用“z”声明字符串字面量
默认四字节,unicode标量值→可以使用带变音符号的字母,中文,日文,韩文,emoji
2.2.2 复合类型
-
元组
元组是把多个其他类型的值组合在一起构成一个复合类型的主要方式
let tup:(i32,f64,u8) = (500 , 6.4 ,1);
将元组拆分叫做解构,就是把元组绑定在同等数量的一个元组上,然后输出值
可以使用.idx 来访问他们
-
数组
数组中每个数的值需要是相同的,rust中的数组长度是固定的
数组的声明:
- let months = [” a “,” b “,…];
- let a:[u8;5] = [1,2,3,4,5];
- let a =[3;5];数组中的初始值都是3
可以使用索引访问数组
不可以越界访问数组,越界访问rust会发生panic
2.2.3 String类型
- 因为并非所有字符串的值都能在编写代码时候就知道,所以String被分配在堆上
- 使用from函数基于字符串字面值来创建String
let s = String::from("hello");
//::是运算符,允许将特定的from函数至于String类型的命名空间下
s.push_str(",world");
println("{}",s);
2.3 函数
- Rust中函数采用snake case规范风格,所有函数名和变量名采用小写加下划线的方式
- 通过fn后面加函数名和圆括号的方式来定义函数
2.3.1 参数
- 参数是特殊变量,是函数签名的一部分
- 参数必须声明它的类型
fn print_labeled_measurement(value: i32, unit_label: char) {
println!(“The measurement is: {value}{unit_label}”);
}
参数类型都声明在参数后面
2.3.2 语句和表达式
- 语句不返回值
- 表达式返回一个计算值
- 因此可以将一个表达式赋给一个语句
fn main(){
let y = {
let x = 3;
x+ 1//注意这里的x+1后面没有分号,是一个表达式
}
}
2.3.3 具有返回值的函数
-
在函数()后标识→ 类型、
因此在函数的最后应该是一个不带有分号的表达式
2.4 注释
- 常用的注释为 //
2.5 控制流
2.5.1 if表达式
-
if number < 5 {
}else{
}
-
if - else if - else 组合结构处理问题
-
rust只会执行第一个为true的代码块,剩下的都不会检查了
-
在let中使用if
let condition = true;
let number = if condtion {5} else {6};
但是conditon{}else{}中的返回值必须是匹配的
2.5.2 循环重复执行
-
loop
重复执行知道满足要求
break 后面可以加返回值
-
循环标签
可以在loop前面打一个标签,然后在需要结束的地方结束loop
‘counting_up:loop{
//...
break ‘counting_up;
//...
}
-
while条件循环
当条件为true的时候,执行循环
-
for进行遍历集合中的元素
a = [10,20,30,40,50];
for element in a {
//...
}
for number in (1...4).rev() {
}