Skip to content

3. Rust 语法

3.1 变量和可变性

  • 声明变量使用 let 关键字,默认情况下变量是不可变的(Immutable)
  • 使用 mut 关键字声明可变变量(Mutable Variable)

常量和不可变变量有一些区别:

  • 常量使用 const 修饰,且类型需要被标注
  • 常量不能使用 mut,因为常量永远不可变
  • 常量可以在任何作用域中声明,包括全局作用域
  • 常量只能被设置为常量表达式,不能是函数调用的结果或任何其他只能在运行时计算得到的值
rust
const MAX_POINTS: u32 = 100_000;

Rust 命名规范

常量使用全大写字母,单词之间使用下划线分隔。函数名和变量名使用蛇形命名法(Snake Case)。

隐藏(Shadowing):可以声明一个与之前变量同名的新变量,新变量会覆盖之前的变量。

rust
let x = 5;
let x = x + 1;
let x = x * 2;

隐藏与 mut 本质不同,隐藏会创建一个新变量,而 mut 会改变原变量的值。隐藏可以绑定到新的类型。

3.2 数据类型

Rust 是一种静态类型(Statically Typed)语言,编译器在编译时就必须知道所有变量的类型。

Rust 有两种数据类型:标量(Scalar)和复合(Compound)。

Rust 会执行类型推断(Type Inference),根据变量的值推断其类型。但如果有多种可能的类型,需要显式标注类型,否则编译器会报错,例如下面的代码不能通过编译:

rust
fn main() {
    let guess = "42".parse().expect("Not a number!");
    println!("{}", guess);
}

Rust 的标量类型主要有四种:整数、浮点数、布尔值和字符。

整数类型

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize

一般使用 usize 类型来表示索引,其大小取决于运行程序的计算机架构。

整数字面值有下面几种表示方法:

数字字面值例子
十进制98_222
十六进制0xff
八进制0o77
二进制0b1111_0000
字节(u8b'A'

在调试模式下,整数如果发生溢出则会抛出 panic,而在发布模式下则不会检查。

浮点数类型

Rust 有两种浮点数类型:f32f64,默认类型是 f64

rust
let x = 2.0; // f64
let y: f32 = 3.0; // f32

布尔类型

布尔类型有两个值:truefalse

字符类型

Rust 的 char 类型使用单引号,且占用 4 个字节。

3.3 复合类型

Rust 有两种复合类型:元组(Tuple)和 数组(Array)。

rust
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup;
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = tup.2;

数组和元组一样,长度都是固定的。

rust
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];

如果你希望数据存放在栈上,且有固定大小,可以使用数组。如果数据大小不固定,可以使用 Vector

数组的类型是 [T; N]T 是元素的类型,N 是数组的长度。下面声明数组的类型:

rust
let a: [i32; 5] = [1, 2, 3, 4, 5];

可以使用初始值缩略:

rust
let a = [3; 5]; // 等价于 let a = [3, 3, 3, 3, 3];

数组使用 [] 访问元素,如果访问越界会导致 panic,编译会尝试检查,但不一定能检查出问题。

3.4 函数

函数使用 fn 关键字声明,函数名使用蛇形命名法。

rust
fn main() {
    println!("Hello, world!");
}

函数的形参必须标注类型。

Rust 是一门基于表达式的语言,函数体的最后一个表达式会被隐式返回。函数的定义是语句,语句没有返回值,也不能被赋值到变量上。

函数可以标注返回值类型:

rust
fn five() -> i32 {
    5
}

Rust 支持单行注释和多行注释,与 C/C++ 和 JavaScript 语法一致。

rust
// 单行注释
/*
多行注释
*/

3.5 控制流

if 表达式:

rust
fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}

建议使用 match 表达式替代复杂的 if-else 表达式。

if 是一个表达式,可以在 let 语句的右侧使用。if 的每个分支都必须返回相同类型的值。

rust
let condition = true;

let number = if condition {
    5
} else {
    6
};

注意:if-else 分支的返回值必须是兼容的类型。

loop 循环是一个无限循环,可以使用 break 退出循环,break 后可以返回一个值。

rust
let mut counter = 0;

let result = loop {
    counter += 1;

    if counter == 10 {
        break counter * 2;
    }
};

println!("The result is {}", result);

while 循环则与其他语言类似。

for 循环可以遍历一个集合中的每一个元素。

rust
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
    println!("the value is: {}", element);
}

Range 类型可以生成一个范围:

rust
for number in (1..4).rev() {
    println!("{}!", number);
}
println!("LIFTOFF!!!");

Range 生成的范围不包含结束值,如果需要包含结束值,可以使用 ..=.rev() 可以反转范围。