【笔记】Rust学习笔记

前言

Rust是由Mozilla主导开发的通用、编译型编程语言。设计准则为“安全、并发、实用”,支持函数式、并行式、过程式以及面向对象的程式设计风格。(维基百科

安装Rust

Linux

1
2
curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env

MacOS

直接安装

1
brew install rust

手动安装

1
2
brew install rustup-init
rustup-init
1
2
3
4
5
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation

1

查看Rust版本

1
rustc --version
1
rustc -V

编写Rust代码

  • Rust程序会自动导入prelude库,无需手动导入即可直接使用
  • main()函数为程序的入口
main.rs
1
2
3
fn main() {
...
}

编译单个Rust代码文件

<file>.rs:Rust源码文件

1
rustc <file>.rs

通过Cargo管理项目

查看Cargo版本

  • Cargo在Rust安装时同时安装
1
cargo --version

在当前目录初始化项目

  • 在当前目录自动创建Cargo.toml配置文件,初始化当前目录作为Cargo项目
1
cargo init

创建一个新的项目

  • 通过cargo命令创建一个新的项目

  • 自动创建Cargo.toml配置文件

  • 自动初始化一个git仓库

  • 自动创建src目录,并在src目录下创建main.rs文件

<project_name>:项目名称

1
cargo new <project_name>

项目配置文件

package:当前项目配置

name:项目名称
version:项目版本
edition:使用的Rust版本

dependencies:第三方依赖crate的配置

Cargo.toml
1
2
3
4
5
6
7
8
[package]
name = "demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

编译Cargo管理的项目

  • 第一次编译时会在项目根目录生成cargo.lock文件
  • 编译后会在target目录下生成可执行文件
1
cargo build

编译并运行Cargo管理的项目

1
cargo run

为发布而编译

  • 此时会对编译后的可执行文件优化,但是编译时间更慢
1
cargo build --release

只检查代码不编译

1
cargo check

注释

1
2
// 单行注释
/* 多行注释 */

TODO

1
todo!()

控制台输出

1
println!("输出内容");

格式化输出

  • 通过{}作为占位符
1
println!("{}", "输出内容");

控制台输入

  • 返回io::Result类型的值OkErr

引入库

1
2
3
4
5
6
use std::io;

fn main() {
let mut str = String::new();
io::stdin().read_line(&mut str).expect("读取输入错误");
}

使用全名

1
2
3
4
fn main() {
let mut str = String::new();
std::io::stdin().read_line(&mut str).expect("读取输入错误");
}

定义变量

变量的命名规范

  • 只能包含小写字母、大写字母、数字、下划线
  • 只能以小写字母、大写字母、下划线开头
  • 变量名区分大小写

定义不可变的变量(immutable)

  • 不可变变量定义后不能被重新赋值
1
let 变量名 = 值;
1
let 变量名:数据类型 = 值;

定义可变的变量

1
let mut 变量名 = 值;
1
let mut 变量名:数据类型 = 值;

可变的引用

1
&mut 变量名 

变量的隐藏

  • 定义同名变量,新的变量会将旧的变量隐藏,只保留最后一次定义的结果
1
2
let 变量名 = 值;
let 变量名 = 值;

隐藏变量并且改变数据类型

1
2
let 变量名:数据类型1 = 值;
let 变量名:数据类型2 = 值;

定义常量

  • 常量名称通常是大写字母
  • 定义常量时必须指定数据类型
  • 常量不能被隐藏,也不能被重复定义
  • 常量在编译时就替换为具体的值
1
const 常量名:数据类型 = 值;

运算符

算数运算符

  • +-*/%

关系运算符

  • ><>=<===!=

逻辑运算符

  • &&||!

位运算

  • &|^!<<>>

分支语句

if

1
2
3
if 条件表达式 {
条件表达式为真时执行的语句
}
1
2
3
4
5
if 条件表达式 {
条件表达式为真时执行的语句
} else {
条件表达式不为真时执行的语句
}
1
2
3
4
5
6
7
if 条件表达式1 {
条件表达式1为真时执行的语句
} else if 条件表达式2 {
条件表达式2为真时执行的语句
} else {
条件表达式1和条件表达式2都不为真时执行的语句
}

match

  • Rust的match语句有返回值,它把匹配值后执行的第一条语句的结果当作返回值
1
2
3
4
5
let 结果变量名 = match 变量名 {
"值1" => 变量结果为值1时返回的值,
"值2" => 变量结果为值2时返回的值,
_ => 变量结果既不为值1也不为值2时返回的值
}

循环语句

while

1
2
3
while 条件表达式 {
满足条件时反复执行的语句
}

for

遍历有序的整数

  • 遍历[0,1)的整数
1
2
3
for i in 0..1 {
...
}
  • 遍历[1,5]的整数
1
2
3
for i in 0..=1 {
...
}

遍历可迭代对象

迭代后元素保持不变
  • 迭代后元素保持不变,可以再次遍历
1
2
3
4
let list = vec!["", ""];
for item in list.iter() {
...
}
迭代后会将元素移除
  • 迭代后元素移除,不可以再次遍历
1
2
3
4
let list = vec!["", ""];
for item in list.into_iter() {
...
}
迭代时可以修改元素值
1
2
3
4
let mut list = vec!["", ""];
for item in list.iter_mut() {
...
}

loop

  • 无限循环
1
2
3
4
5
6
7
let mut flag = true
loop {
if flag == false {
break;
}
flag = false;
}

所有权

  • Rust中在栈中存储的数据(基本类型数据)不会涉及到所有权的迁移
  • Rust中在堆中存储的数据(引用类型数据)有所有权,每个数据只能由一个变量所有,当发生转移的时候新的变量获得所有权,旧的变量失去所有权,失去所有权的变量将不能再使用这个变量

转移所有权

通过赋值转移所有权

1
2
let 变量名1:引用类型 = 值;
let 变量名2 = 变量名1;

通过函数参数的传递转移所有权

1
2
let 变量名1:引用类型 = 值;
函数名(变量名1);

借用

  • 通过使用&修饰的变量实现对所有权的借用
  • 在函数执行结束会自动归还所有权
1
2
let mut 变量名1:引用类型 = 值;
函数名(&mut 变量名1);

解构结构体

1
2
3
4
5
6
7
let 结构体变量名 = 结构体名{
属性名: 属性值
};

let 结构体名 {
属性名: 属性名
} = 结构体变量名;

只解构部分属性

..:忽略其他属性

1
2
3
4
5
6
7
8
9
let 结构体变量名 = 结构体名{
属性名1: 属性值,
属性名2: 属性值
};

let 结构体名 {
属性名1: 属性名1,
..
} = 结构体变量名;

判断是否能正常解构

1
2
3
4
5
6
7
8
9
10
let 结构体变量名 = 结构体名{
属性名1: 属性值,
属性名2: 属性值
};

if let 结构体名 {属性名: 属性名} = 结构体变量名 {
解构成功时执行的语句
} else {
解构失败时执行的语句
}
1
2
3
4
5
6
7
8
let 结构体变量名 = 结构体名{
属性名1: 属性值,
属性名2: 属性值
};

while let 结构体名 {属性名: 属性名} = 结构体变量名 {
解构成功时反复执行的语句
}

完成

参考文献

哔哩哔哩——软件工艺师
哔哩哔哩——面向加薪学习
知乎——赵东颖