03
基础语法:变量、类型、函数、控制流
Variables · Types · Functions · Control Flow
Rust 语法 80% 跟你写过的 Java/C 像,剩下 20% 的差异才是重点——默认不可变、表达式导向、match 穷尽匹配。这一章快速过一遍,盯着跟 Java 不一样的地方看。
变量与可变性:let 默认只读
论为什么默认不可变
Java 里 int count = 0; 随便改,编译器不管。Rust 反过来:let x = 5; 默认只读,想改必须显式写 let mut x = 5;。这逼你写代码时就想清楚"这变量会不会变",从根上减少意外修改的 bug。
fn main() {
let x = 5; // 默认不可变
// x = 6; // 编译报错:cannot assign twice to immutable variable
let mut y = 5; // mut 才允许改
y = 6;
// const 是编译期常量,必须标类型,不能用 mut
const MAX_POINTS: u32 = 100_000;
// shadowing 变量遮蔽:重新 let 一个同名变量,类型还能变
let spaces = " ";
let spaces = spaces.len(); // 从字符串"遮"成数字,合法
println!("{} {} {}", x, y, spaces);
}
$ cargo run
5 6 3
数据类型:标量与复合
| 类别 | 类型与说明 |
|---|---|
| 有符号整数 | i8 i16 i32 i64 i128 isize(指针宽度,跟随机器位) |
| 无符号整数 | u8 u16 u32 u64 u128 usize(最常用 i32 / u64) |
| 浮点 | f32 f64,默认 f64(跟 Double 一样) |
| 布尔 | bool,值 true / false |
| 字符 | char,4 字节的 Unicode 标量值,不是单字节 ASCII('中'、'é'、'字' 都合法) |
| 元组 | (i32, f64, char),固定长度可混合类型,let (a, b, c) = t; 解构 |
| 数组 | [i32; 5],固定长度,栈上分配;变长的用 Vec(第 10 章) |
fn main() {
let tup: (i32, f64, bool) = (42, 3.14, true);
let (a, b, c) = tup; // 解构
println!("{} {} {}", a, tup.0, c);
let arr: [i32; 3] = [1, 2, 3];
println!("第一个元素 {},数组长度 {}", arr[0], arr.len());
// 类型推断:大多数情况不用手写类型
let inferred = 100; // 推断成 i32
let big: i64 = 100; // 需要时再标注
// 类型别名:给长类型起外号,不创建新类型
type Age = i32;
let _age: Age = 18;
println!("{} {}", inferred, big);
}
函数:参数必须标类型
// Rust 函数参数必须标注类型,这是它跟 JS/Python 的硬区别
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一行没有分号 = 表达式 = 返回值,等价 return a + b;
}
// 发散函数:! 返回类型表示"永远不返回"(比如直接 panic 或 loop 死循环)
fn diverges() -> ! {
panic!("我跑不到头");
}
fn main() {
println!("2 + 3 = {}", add(2, 3));
}
论表达式 vs 语句:Rust 的灵魂细节
语句干一件事但不返回值(结尾带分号);表达式求值并返回一个值(不带分号)。所以块 { } 本身也是表达式,最后一行不带分号就成了块的值——这就是为什么 if、loop 都能直接当右值赋值。
控制流:if 是表达式,match 穷尽
fn main() {
// if/else 是表达式,可以直接赋值(所有分支类型要一致)
let n = 7;
let msg = if n > 5 { "大于五" } else { "小于等于五" };
// loop 可以 break 带回值
let mut count = 0;
let result = loop {
count += 1;
if count == 3 { break count * 10; } // break 后的值就是 loop 的返回值
};
// for in 遍历区间 [0, 5),Rust 没有 while 风格的三段 for
for i in 0..3 { print!("{} ", i); }
// match 必须穷尽,编译器逼你处理所有情况
let score = 85;
let grade = match score {
90..=100 => "A",
70..=89 => "B",
0..=69 => "C",
_ => "无效分", // _ 通配符兜底,覆盖剩下的所有
};
println!("\n{} {} {} {}", msg, result, grade, score);
}
$ cargo run
0 1 2
大于五 30 B 85
- 文档注释:
///给下面的项写文档(支持 Markdown,里面的代码还会被cargo test当测试跑);//!是给整个模块写文档,放文件开头。 - if let / while let:只关心一种情况时简化 match,
if let Some(v) = opt { ... }。