变量声明
Rust 使用 let
关键字声明变量,和其他新兴语言一样,默认情况下是 Immutable 的。需要使用
mut
关键字使其可变。
fn main() {
let x = 5;
println!("The value of x: {}", x);
let mut y = 5;
println!("The value of y: {}", y);
}
请注意,这里虽然没有写类型,但不代表 Rust
是动态的。这是类型推断,相当于编译器自动帮你写成了
let x: i32 = 5;
。
基本类型和 &str
(字符串自变量)
可以被声明为编译时常量:
const MAX_POINTS: u32 = 100_000; // compile-time constant
fn main() {
const STRING: &str = "123123";
println!("The value of MAX_POINTS: {}", MAX_POINTS);
}
常量必须显式写明类型。同时 top-level
或局部声明都是可以的。
Shadow
虽然不允许修改变量,但 Rust 允许 Shadow 一个变量的名称。比如:
let a = 1;
let a = 100;
然而,我不建议这种做法,很多语言也不建议这种做法。建议读者自行斟酌。
注释
// 单行注释
/*
* 多行注释
* /*
* * 可以嵌套
* */
*/
///
/// 文档注释
///
基本类型
基本类型(primitives),也叫原生类型、原语。是组成所有数据结构的基本元素。
整数类型
长度 | Signed / 有符号 | Unsigned / 无符号 |
---|---|---|
8 位 | i8 | u8 |
16 位 | i16 | u16 |
32 位 | i32 | u32 |
64 位 | i64 | u64 |
128 位 | i128 | u128 |
架构特定 | isize | usize |
Rust 的基本类型关键字非常简洁易懂,直接就是类型缩写 +
所占空间,不必纠结 int
long
long long
long int
short
的意义。
同时少有的支持 128 位数据类型。
isize
和 usize
即根据平台使用不同的长度,如
32
位架构上,就占 32
位
,最常用来存数组下标。
Rust 也支持不同进制的整数字面量:
字面量 | 示例 |
---|---|
十进制 | 98_222 |
十六进制 | 0xFF |
八进制 | 0o77 |
二进制 | 0b1111_000 |
字节(仅 u8 ) | b'A' |
可以使用 _
分隔数字,便于阅读。
浮点类型
Rust 的浮点数遵循 IEEE 754
标准。具有 f32
和 f64
两种长度可选。默认为 f64
。
浮点数可以省略小数部分,如
0.
,但不可省略点号和整数部分。
字符
关键词为 char
,字面量使用单引号包围,可存任意 Unicode
定义的字符,占 4 字节。
let a = 'a'
let alpha = 'α'
let emoji = '😄' // 大多数 emoji 都可以存为字符
布尔
关键词为 bool
,字面量 true
或
false
,占 1 字节。
Unit 类型
空元组:()
。尽管是元组,但它是一种特殊的类型,而不是复合类型,因为不包含多个值。
复合类型
数组:
[1, 2, 3]
- Rust 的数组索引和多数 C-like 语言一样,从 0 开始
- 数组的长度是固定的,所以类型注解应写成
let arr: [i32; 5] = [1,2,3,4,5]
- 多个同样的值可以使用
[0; 5]
这种语法,相当于[0, 0, 0, 0, 0,]
- 在编译时,Rust 能够检测部分数组越界。如
let a = [1,2,3]; a[10];
会直接不过编译。 - 在运行时,若数组越界了,将会直接 panic 退出程序,而不是继续执行。
元组:
(1, true)
类型注解类似这样:
(i32, bool)
当元素多于
3
个时,建议使用结构体定义。可以直接访问对应的类型:
x.0
x.1
解构声明:
let (x, y, z) = (500, 6.4, 1);
数组和元组的区别在于:数组只能存一种类型;而元组能存多种类型。
字面量后缀
可以使用对应关键字当作类型后缀。例如:
let a = 100i64;
let b = 100i32;
let c = 100i8;
let d = 10.123f32;
let f = 10.112312312f64;
操作符
这部分和大多数类 C 语言一样。就不列出全表了。
值得一提的是,Rust 类似很多新语言(如 Swift),没有 ++
操作符,避免了各种魔怔写法。建议使用 value += 1
替代。
优先级不明晰的时候,建议括号包裹即可,不用背优先级。
函数
函数使用 fn
声明,函数名使用 snake_case
风格:
fn function() { // 隐式返回 Unit 类型 ()
println!("Hello Function!");
;
another_function()}
fn another_function() {
println!("Another function.");
}
参数可以这样写:
fn main() {
5, 'g');
another_function(}
fn another_function(x: i32, lable: char) {
println!("The value of x is: {}{}", x, lable);
}
Rust 刻意不支持默认参数,也不支持函数重载。
Rust 允许将不写分号的语句直接返回,而不用写 return
:
fn return_no_semicolon() -> i32 {
123123
}
然而我认为这无疑是一种垃圾设计,舍本逐末。为了这里一点的方便,让其他所有地方都要写分号。
况且为何不直接:
fn return_no_semicolon() -> i32 = 123123
控制流
条件
if-else
这里用到了 rand
库,编辑 Cargo.toml
[dependencies]
rand = "0.8.0"
use rand::{thread_rng, Rng}; // 导包
fn main() {
// 这里的 ..= 是闭区间, 也就是说包括 1 和 100
// 与之对应的有 .. 是左闭右
let num = thread_rng().gen_range(1..=100);
let cmp_num = thread_rng().gen_range(1..=100);
if num < cmp_num {
println!("{num} is greater than {cmp_num}!")
} else {
println!("{num} is not greater than {cmp_num}!")
}
}
和其他语言类似,Rust 可以省略包裹条件的括号,但不能省略大括号。
Rust 的条件必须是布尔类型,以下代码会报错:
if 1 {}
if-else-if
// 后面将会省略 main 函数和生成 num 的代码
if num % 3 == 0 {
println!("{num} is is divisible by 3!")
} else if num % 4 == 0 {
println!("{num} is is divisible by 4!")
} else if num % 5 == 0 {
println!("{num} is is divisible by 5!")
} else {
println!("{num} is not divisible by 3, 4, 5.")
}
match
match num {
1 => println!("1"),
2 => println!("2"),
=> println!("Other number"),
_ }
match
要求分支必须是穷尽的,常常用来处理枚举。后面讲到枚举的时候再详细介绍。
作为表达式
穷尽的 if
和 match
允许做看作表达式,用于赋值。
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {}", number);
}
循环
while
let mut count = 0;
while count < 5 {
+= 1;
count println!("Again! {count}");
}
loop
死循环,类似于 while true {}
,但对 loop
有着不同的语义。Rust 建议任何能用 while true {}
的地方都用
loop
。
break & continue
break
用于跳出整个循环。continue
用于跳过本次循环。
fn main() {
let mut count = 0;
while count < 5 {
+= 1;
count print!("{count} ");
if count == 1 {
continue;
}
if count == 3 {
break;
}
}
}
label
如果存在嵌套循环,可以使用循环标签,跳过指定的循环,而不是最内层循环。
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {}", count);
let mut remaining = 10;
loop {
println!("remaining = {}", remaining);
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
-= 1;
remaining }
+= 1;
count }
println!("End count = {}", count);
}
/*
Output:
count = 0
remaining = 10
remaining = 9
count = 1
remaining = 10
remaining = 9
count = 2
remaining = 10
End count = 2
*/
for
for count in 1..=5 {
println!("Again! {count}");
}
// rev() 用于逆序, 此处会从 5 倒数到 1
for count in (1..=5).rev() {
println!("Again! {count}");
}
foreach
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("The value is {element}");
}