Rust学习笔记
安装
curl https://sh.rustup.rs --sSf |sh
常用命令
- rustup update :来更新Rust版本
- rustup self uninstall : 卸载rustup及Rust工具链
- rustc --version:检查Rust是否被正确安装,
- 如果一切正常,在命令输出就会看到格式为「最新稳定版本的版本号」、「当前版本的hash」、「版本的提交日期」
- rustc 1.76.0 (07dca489a 2024-02-04)
- rustup doc: 在浏览器中打开在安装工具再执行过程中在本地生成的「离线文档」
Hello Rust
- 创建一个文件夹
mkdir ~/projects
cd ~/projects
mkdir hello_rust
cd hello_rust
- 编写并运行Rust程序
创建一个名为main.rs的「源文件」。在命令规则上,Rust文件总是以.rs扩展名结尾。
fn main(){
println!("Hello,Rust");
}
- 编译并运行
rustc main.rs
./main
Hello Cargo
每次运行rustc都比较繁琐,项目小还可以忍受吗,但是如果随着项目增大,这无疑是一种折磨。所以,在实际运用中,我们用Rust构建工具:Cargo
Cargo是Rust工具链中「内置」的构建系统及「包管理器」.由于它可以处理众多诸如构建代码、下载编译依赖库等繁琐但重要的任务,所以绝大部分的Rust用户都选择它来管理自己的Rust项目。
- 用Cargo创建一个项目
cargo new hello_cargo
cd hello_cargo
Cargo使用TOML(TOM's Obvious,Minimal Language)作为标准的配置格式。
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
首行文本中的[package]
是一个「区域标签」,它表明接下来的语句会被用于当前的程序包。紧随标签后的3行语句提供了Cargo编译这个程序时需要的配置信息,它们分别是
- 程序名-
hello_cargo
- 程序版本号 - 0.1.0
- Rust版本号 - 2021
最后一行文本中
[dependencies]
同样是一个区域标签,它表明随后的区域会被用来声明项目的依赖。在Rust
中,把代码的集合称为包Crate
。
- 使用
cargo build
来编译构建项目, 它会在「项目根目录」下创建一个名为Cargo.lock的新文件,这个文件记录了「当前项目所有依赖库的具体版本号」。「不要手动编辑其中的内容,Cargo可以帮助你自动维护它」 - 使用
cargo run
命令依次完成「编译」和「执行」任务。 - 使用
cargo check
的命令来「快速检查当前代码是否可以通过编译」 - 使用命令
cargo build --release
在「优化模式」构建并生成可执行程序
基础语法
变量与可变性
在Rust中变量「默认是不可变」的。但你可以通过在「声明的变量名称前」添加
mut
关键字来使其可变。
fn main() {
// let x =7;
// x = 8; 编译无法通过
let mut x =7;
println!("x的值是:{}",x);
x = 8;
println!("x的值是:{}",x);
}
可以使用变量遮蔽
来修改变量的值, 如:
fn main() {
let x =5;
let x = x + 1;
let x = x * 2;
println!("x的值为:{}",x)
}
遮蔽机制与
mut
的一个区别在于:由于重复使用let
关键字会创建出「新的变量」,所以「可以在复用变量名称的同时改变它的类型」。
- 变量的不可变与常量之间是有差别的
- 不能用
mut
关键字来修饰一个常量。常量「不仅是默认不可变的,它还总是不可变」的 - 使用const关键字而不是let关键字来声明一个常量,且常量在声明的同时,「必须显示地标注值的类型」
- 常量可以被声明在任何作用域中,甚至包括全局作用域。
- 「只能将常量绑定到一个常量表达式上」,而无法将一个函数的返回值或其他需要在运行时计算的值绑定在常量上。
- 不能用
- 约定俗成地使用「下划线分隔的全大写字母来命令一个常量」
fn main() {
const MAX_AGE:u32 = 100;
}
数据类型
- 在
Rust
中内建了4
种基础的标量类型:
整数类型
长度 | 有符号 | 无符号 | 取值范围 |
---|---|---|---|
8-bit | i8 | u8 | |
16-bit | i16 | u16 | |
32-bit | i32(Rust默认) | u32 | |
64-bit | i64 | u64 | |
arch | isize | usize |
- 对于一个位数为n的有符号整数类型,它可以存储从-(2n-1)到(2n-1-1)范围内的「所有整数」。
- 而对于无符号整数类型而言,则可以存储从0到(2n-1)范围内的「所有整数」。
isize
和usize
两种特殊的整数类型,它们的长度取决于程序运行的目标平台: 在64
位架构上,它们就是64
位的, 在32
位架构上,它们就是32
位的。 当Rust
发生整数溢出时候,会执行「二进制补码环绕」。也就是说,「任何超出类型最大值的整数都会被环绕为类型最小值」
。
浮点数
Rust
还提供了两种基础的浮点数类型,「浮点数也就是带小数点的数字」。这两种类型是f32
和f64
,它们分别占用了32
位和64
位空间。
在
Rust
中,默认会将浮点数字面量的类型推导为f64
。f32
和f64
类型分别对应这标准中的「单精度」
和「双精度浮点数」
布尔值
Rust
的布尔类型只拥有两个可能的值true
和false
,它「只会占据单个字节的空间大小」。使用bool
来表示一个布尔类型。
fn main(){
let t = true;
let f:bool = false;
}
字符类型
在Rust
中,char
类型被用于描述语言中最基础的「单个字符」。
fn main(){
let c = 'a';
}
char
类型使用「单引号」
指定,字符串使用「双引号」
指定。- 在
Rust
中char
类型「占4字节」
,是一个Unicode标量值,这意味着它可以表示比ASCII
多的字符内容。
在Rust提供了两个「内置」的基础复合类型:Tuple
(元组)和Array
(数组)
元组
元组可以将其他「不同类型的多个值」组合进一个复合类型中。元组还拥有一个固定的长度:你「无法在声明结束后增加或减少其中的元素数量」。
- 为了创建元组,需要把一系列的值使用「逗号分隔」后放置到一对「圆括号」中。元组「每个位置都有一个类型」,这些类型不需要是相同的。
fn main(){
let tup:(i32,f64,u8) = (500,7.8,1);
}
- 可以使用「模式匹配」来解构Destructuring元组
fn main(){
let tup:(i32,f64,u8) = (500,7.8,1);
let (x,y,z) = tup;
}
- 还可以通过「索引」并使用点号(
.
)来访问元组中的值
fn main(){
let tup:(i32,f64,u8) = (500,7.8,1);
let firstValue = x.0;
let secondValue = x.1;
}
数组
在数组中存储多个值的集合。与元组不同,「数组中每一个元素都必须是相同类型」。 Rust
中「数组拥有固定的长度,一旦声明就再也不能随意更改大小」
fn main(){
let a = [1,2,3,4,5];
}
可以使用一对「方括号」,并在方括号中填写数组内所有元素的类型,「一个分号及数组内元素的数量」。
fn main(){
let a:[i32;5] = [1,2,3,4,5];
}
数组是「一整块分配在栈上的内存组成」,可以通过「索引」来访问一个数组中所有元素。
函数
Rust
代码使用蛇形命名法Snake Case
来作为规范函数和变量名称的风格。蛇形命名法「只使用小写的字母进行命名,并以下画线分隔单词」。
fn main() {
another_function(5)
}
fn another_function(x:i32){
println!("传入函数的变量为:{}",x)
}
- 在
Rust
中,函数定义以fn
关键字开始并紧随函数名称与一对圆括号,还有一对花括号用于标识函数体开始和结尾的地方。在函数签名中,你「必须显示地声明每个参数的类型」。- 函数可以向调用它的代码返回值。需要在箭头符号(->)的后面声明它的类型。
fn five() ->i32{
5
}
fn main() {
let x = five();
println!("子函数返回的值为:{}",x)
}
- 可以使用
return
关键字并指定一个值来提前从函数中返回- 但大多数函数都「隐式」地返回了最后的表达式