🦀 Rust学习教程2:基础语法
面向 C++ 工程师的 Rust 基础语法精讲:变量与类型、函数、控制流,辅以与 C++ 的对比、FAQ、练习与总结。读完即可动手写简单程序。

📑 目录
- [零、🚀 从 Hello World 开始](#零、🚀 从 Hello World 开始)
- [一、📦 变量与类型](#一、📦 变量与类型)
- [二、⚙️ 函数](#二、⚙️ 函数)
- [三、🔄 控制流](#三、🔄 控制流)
- [四、💬 表达式与语句](#四、💬 表达式与语句)
- [五、🆚 与 C++ 的区别](#五、🆚 与 C++ 的区别)
- [六、❓ FAQ 常见问题](#六、❓ FAQ 常见问题)
- [七、✏️ 练习](#七、✏️ 练习)
- [八、✅ 总结](#八、✅ 总结)
零、🚀 从 Hello World 开始
确保已安装 rustup 和 Cargo,在终端执行:
bash
cargo new rust_basics
cd rust_basics
在 src/main.rs 中已有默认入口。本教程涉及的语法都可在该项目的 main.rs 或新文件中练习。
rust
fn main() {
println!("Hello, world!");
}
运行:cargo run。下面所有示例均可放在 main 中或单独函数里调用。
本教程知识结构概览:
🦀 Rust 基础语法
变量与类型
let / let mut
标量 整型 浮点 bool char
元组与数组
常量与遮蔽
函数
参数与返回类型
表达式返回值
发散函数
控制流
if / else 表达式
loop while for
表达式与语句
块与分号
注释与打印
📁 cargo new
✏️ 写代码
▶️ cargo run
一、📦 变量与类型
Rust 是静态类型 语言,类型在编译期确定;同时支持类型推断 ,多数情况下不必手写类型。变量默认不可变 ,需要可变时显式写 mut。
1.1 🔒 变量声明:let 与 let mut
rust
fn main() {
let x = 42; // 不可变,类型推断为 i32
let mut y = 10; // 可变
y += 1; // OK
// x += 1; // 编译错误:cannot assign twice to immutable variable
}
记忆要点 :默认不可变,要改就加 mut。
变量
let x = 42
🔒 不可变
let mut y = 10
🔓 可变
可变何时用
需要原地修改时
let mut 显式声明
不可变的好处
编译期保证不改
便于推理与并发
1.2 📊 标量类型(Scalar)
| 类型 | 说明 | 示例 | 与 C++ 对照 |
|---|---|---|---|
| 整型 | 有符号 / 无符号,固定位宽 | i32, u64, i8 |
int32_t, uint64_t |
| 浮点 | f32, f64 |
3.14_f32, 2.0 |
float, double |
| 布尔 | bool |
true, false |
bool |
| 字符 | char,Unicode 标量 |
'中', 'a' |
char(Rust 为 4 字节) |
整型字面量:可加类型后缀与分隔符:
rust
let a = 42_i32; // 有符号 32 位
let b = 0xff_u8; // 十六进制,无符号 8 位
let c = 1_000_000; // 可读性分隔
默认推断 :未指定时,整数推断为 i32,浮点数推断为 f64。
其他标量
f32 f64
bool
char
整型
i8 i16 i32 i64 i128
u8 u16 u32 u64 u128
1.3 🧩 复合类型:元组与数组
元组(Tuple):固定长度、可异构。
rust
let t: (i32, f64, bool) = (42, 3.14, true);
let first = t.0; // 42,通过 .0 .1 .2 访问
let (x, y, z) = t; // 解构
数组(Array):固定长度、同类型,长度是类型的一部分。
rust
let arr: [i32; 5] = [1, 2, 3, 4, 5]; // 类型为 [i32; 5]
let zeros = [0; 10]; // [0, 0, 0, ...],10 个 0
let first = arr[0]; // 下标访问,越界会 panic
与 C++ 对照:Rust 的数组更像 std::array<T, N>,长度固定;动态数组用 Vec<T>(后续阶段会学)。
复合
(T, U, ...) 元组
T; N\] 数组
标量
i8..i128, u8..u128
f32, f64
bool, char
类型
#### 1.4 🌑 常量与变量遮蔽(含作用域)
**常量(const)**:编译期确定,必须带类型,命名习惯全大写+下划线。
```rust
const MAX_POINTS: u32 = 100_000;
```
**变量遮蔽(shadowing)** :用 `let` 再次声明同名变量,新变量可换类型、可覆盖旧值,与 `mut` 不同(`mut` 是原地改,不换类型)。
官方书中的要点:**第二个变量会「遮蔽」第一个,直到它自己再被遮蔽或所在作用域结束**;离开内层作用域后,外层绑定重新可见。
下面用 `println!` 演示:同一作用域内遮蔽、以及**内层作用域遮蔽后离开作用域**的情况。
```rust
fn main() {
let x = 5;
println!("1. 外层 x = {}", x); // 1. 外层 x = 5
let x = x + 1; // 同一作用域内遮蔽,x 变为 6
println!("2. 遮蔽后 x = {}", x); // 2. 遮蔽后 x = 6
{
let x = x * 2; // 内层作用域遮蔽:新 x = 12
println!("3. 内层作用域 x = {}", x); // 3. 内层作用域 x = 12
} // 内层 x 离开作用域,被丢弃
println!("4. 离开内层后 x = {}", x); // 4. 离开内层后 x = 6
}
```
**运行输出**:
```text
1. 外层 x = 5
2. 遮蔽后 x = 6
3. 内层作用域 x = 12
4. 离开内层后 x = 6
```
**作用域与遮蔽关系**(谁可见、何时恢复):
内层作用域 x 外层作用域 x 内层作用域 x 外层作用域 x let x = 5 let x = x + 1 let x = x \* 2 (遮蔽) 块结束,内层 x 丢弃 println → 5 println → 6 println → 12 println → 6 (外层 x 重新可见)
内层块 {}
外层
x = 5
let x = x+1 → x = 6
离开内层后 x 仍是 6
let x = x\*2 → x = 12
**与 C++ 对比**:C++ 没有「同一作用域内同名遮蔽」的惯用写法;Rust 的 shadowing 常用于转换类型或中间变量,且内层遮蔽不会改变外层的绑定,离开内层后外层变量恢复可见。
**换类型的典型用法**(仍用官方书例子):
```rust
fn main() {
let spaces = " ";
let spaces = spaces.len(); // 遮蔽并换类型:&str → usize
println!("spaces 数量: {}", spaces); // 3
}
```
#### 1.5 ✍️ 类型注解何时需要写?
编译器能推断时可以不写;以下情况建议或必须写:
* 函数参数与返回值(见下一节)
* 无法从上下文推断时(如 `let v: Vec