从 hello world 开始
创建一个 main.rs
文件,写入以下内容
1 | fn main() { |
- 使用以下命令进行编译运行
1 | rustc main.rs |
- 也可使用
Cargo
工具进行构建
1 | cargo new ${project_name} |
其中,toml
文件内容如下
1 | [package] |
在 src/main.rs
中写入内容, 使用cargo build/cargo build --release
进行构建,编译产物将会放在target/debug/${project_name} or target/release/${project_name}
下,也可使用cargo run
直接编译运行,也可使用cargo check
来进行编译检查
变量
- 变量与可变性
1 | let x = 5; //不可变 |
- 常量
1 | const SOME_VALUE: u32 = 1001 |
常量使用const
关键字进行声明,常量可以在任何作用域中声明,并且声明常量时必须注明值的类型
- 隐藏
当定义多个同名的变量时,只有之前的变量都会被最后一次定义的变量隐藏,直到最后一次定义的变量作用于结束
1 | let x = 5; |
以上代码,首先将x
绑定到值5
上, 接着通过let x =
创建了新的变量x
,获取初始值并加一,此时x
的值变为6
,接着在花括号创建的作用于内,x
又被隐藏了一次,此时x
的值为12,在作用于结束时,隐藏也结束了,x
又变回6,因此以上程序输出为:
1 | $ cargo run |
隐藏实际上是创建了一个新的同名变量,可以改变变量值类型,并复用这个名字,而mut
关键字无法做到这一点,例如
1 | let spaces = " "; |
数据类型
每一个值都属于某一个数据类型,这将高速Rust编译器它被指定为何种数据,一遍明确数据处理方式,存在两类数据源类型子集:标量与复合
通常编译器可以自动推导数据类型,不过某些情况下需要显示的指定数据类型,例如数据类型可能有多种情况时,例如将字符串转为数字
1 | let num: u32 = "42".parse().expect("Not a number !"); |
标量类型
代表单独一个值,Rust中有四种基本标量类型:整形、浮点型、布尔型以及字符串类型
整型
默认类型为i32
长度 | 有符号 | 无符号 |
---|---|---|
8-bit | i8 |
u8 |
16-bit | i16 |
u16 |
32-bit | i32 |
u32 |
64-bit | i64 |
u64 |
128-bit | i128 |
u128 |
arch | isize |
usize |
而对于数字面值,允许使用类型后缀,例如64u8
为u8
类型的64,也允许使用_
下划线作为分隔符,例如1_000
等价于1000
数字字面值 | 例子 |
---|---|
Decimal (十进制) | 98_222 |
Hex (十六进制) | 0xff |
Octal (八进制) | 0o77 |
Binary (二进制) | 0b1111_0000 |
Byte (单字节字符)(仅限于u8 ) |
b'A' |
关于整型溢出,Debug模式下构建的二进制,在发生溢出时会panic,Release模式下构建的二进制会进行二进制补码操作,来绕回最小值,如256+1 = 0
对于整型溢出,可采用以下方式显示处理
- 所有模式下都可以使用
wrapping_*
方法进行 wrapping,如wrapping_add
- 如果
checked_*
方法出现溢出,则返回None
值- 用
overflowing_*
方法返回值和一个布尔值,表示是否出现溢出- 用
saturating_*
方法在值的最小值或最大值处进行饱和处理
浮点型
f32
与f64
,分别占32位于64位,默认为f64
,浮点型数据都是有符号的
布尔型
1 | let t = true; |
字符串类型
关键字为char
,类型大小为4个字节,并代表了一个Unicode标量值
1 | let c = 'z'; |
复合类型
可将多个值组合成一个类型,存在两种原生的复合类型:元组与数组
元组类型
将多个其他类型的值组合仅一个复合类型,元组长度固定,一旦声明,其长度不会变化
1 | let tup: (i32, f64, u8) = (500, 1.23, 1); |
当想从元组中获取单个值时, 可以使用模式匹配来结构元组值,例如
1 | let tup = (500, 1.23, 1); |
也可使用.
来进行访问,例如tup.0
即为第一个值500
不带任何值的元组有个特殊的名称,叫做 单元 元组。这种值以及对应的类型都写作 ()
,表示空值或空的返回类型。如果表达式不返回任何其他值,则会隐式返回单元值。
数组类型
数组中的每个元素类型必须相同,且数组的长度是固定的,数组在栈上分配空间
1 | let array = [0, 1, 2, 3, 4, 5]; |
函数与控制流
函数
使用关键字fun
声明,函数名与变量名使用Unix风格,小写字母,并使用下换线分割单词
1 | fn main() { |
Rust 不关心函数定义所在的位置,只要函数被调用时出现在调用之处可见的作用域内就行。
函数的参数
函数的参数必须声明参数类型,多个参数使用逗号分割
1 | fn main() { |
语句和表达式
- 语句 执行一些操作但不返回值的指令,以分号结尾
- 表达式 计算并产生一个值
1 | let a = 1; //语句不会返回任何值 |
在rust中,函数调用是一个表达式。宏调用是一个表达式。用大括号创建的一个新的块作用域也是一个表达式
1 | let a = { |
具有返回值的函数
1 | fn ret() -> i32 { |
控制流
if
表达式
if
表达式使用的值必须为bool
类型
1 | let num = 3; |
if
也可在let
中使用,但是需要每个分支都必须是相同的类型
1 | let flag = true; |
循环
loop循环
无条件的循环,可以使用break
从循环跳出,同时可以返回一个值,也可以使用continue
跳过循环
1 | loop { |
break
和continue
仅能控制当前的循环,对于嵌套的循环,可以配合标签一起使用来控制循环
1 | let mut num = 0; |
while
条件循环
1 | let mut num = 3; |
for
遍历集合
1 | let a = [10, 20, 30, 40, 50]; |