📚 目录
- 什么是控制流?Rust 有什么特别?
if
表达式完整语法loop
/while
/for
三种循环写法match
表达式 +_
通配符深入解释if let
表达式用法与场景- Option、Some、None 全面通俗讲解
"Tom"
和"Tom".to_string()
有啥本质区别?- 什么叫“你需要完整拥有这个字符串”?
- 总结:从语法到思想的控制流精通路线
1️⃣ 什么是控制流?Rust 又有什么不同?
控制流就是**程序根据情况“怎么走”**的能力。
在 Rust 中,控制流不只是控制路径,更是表达式,也就是说,大部分结构都能返回值,不是单纯“执行一下就完了”。
2️⃣ if
表达式语法(可以返回值!)
let score = 75;
let result = if score >= 60 {
"及格"
} else {
"不及格"
};
println!("成绩是:{}", result);
✅ Rust 中
if
是表达式,意思是它有返回值,能被赋值。
注意:if
和 else
返回的值必须是相同类型!
3️⃣ 循环语法:loop / while / for
🔁 loop
(死循环 + 可返回值)
let mut count = 0;
let result = loop {
count += 1;
if count == 3 {
break count * 2;
}
};
println!("结果:{}", result); // 输出:6
🔁 while
(条件成立就循环)
let mut n = 3;
while n > 0 {
println!("倒数:{}", n);
n -= 1;
}
🔁 for
(遍历范围或集合)
for i in 1..4 {
println!("{}", i); // 输出 1, 2, 3(不含4)
}
let names = vec!["Tom", "Amy"];
for name in names {
println!("你好,{}", name);
}
4️⃣ match
表达式 + _
通配符的真正含义
基本用法
let score = 45;
let level = match score {
90..=100 => "优秀",
60..=89 => "及格",
_ => "不及格", // 通配符:兜底处理
};
println!("成绩等级:{}", level);
❓ _
是什么?
_
是一个“通配符”,意思是:“不管其他是什么,统统算进来”;- 它在
match
中的作用相当于 JavaScript 的default
、Python 的else
分支; - Rust 的
match
要求你必须穷举所有可能的分支,所以_
是一个通用的“兜底方案”。
✅
_
的本质含义是:“我不关心这个值具体是多少,你只管来了就处理成这样。”
示例:也可以只打印
match day {
1 => println!("星期一"),
2 => println!("星期二"),
_ => println!("其他天"), // 不管你是3、4、99、9999,全算“其他”
}
5️⃣ if let
:只匹配一种情况的快捷方式
原始 match
写法
let name = Some("Tom".to_string());
match name {
Some(n) => println!("名字是:{}", n),
None => println!("没有名字"),
}
if let
简写版本
if let Some(n) = name {
println!("名字是:{}", n);
} else {
println!("没有名字");
}
✅ 适合只关注
Some(x)
一种情况的时候,更加清爽!
6️⃣ Option / Some / None 的原理与通俗解释
❓ 为什么需要 Option
?
在 C/Java 中,很多人因为空指针(null)访问导致崩溃。Rust 不允许出现“空值”,而是用 Option<T>
来明确告诉你:这个值可能有,可能没有!
let name: Option<String> = Some("Tom".to_string());
let nickname: Option<String> = None;
✅ Option 是啥?
enum Option<T> {
Some(T), // 有值
None // 没值
}
你必须显式处理这两种情况,编译器才放行。这就是 Rust 保证“安全”的核心手段!
❗ 为什么 Some("Tom")
报错?
看起来没毛病吧?
let name: Option<String> = Some("Tom"); // ❌ 报错
我们拆开来看:
写法 | 类型 | 属于谁 |
---|---|---|
"Tom" |
&str |
静态字符串切片(不可变引用) |
"Tom".to_string() |
String |
有所有权、堆上分配 |
String::from("Tom") |
String |
等价于上面 |
🧠 什么是“你需要完整拥有这个字符串”?
当你声明:
let name: Option<String>
你就等于说:“我要拥有一个可变的堆上字符串,我可能有,也可能没有。”
Rust 的 String
是:
- 存在堆上的数据(可以动态增长)
- 有“所有权”:谁负责创建,就负责释放
- 可变的
但是 "Tom"
是:
- 固定存在程序里的静态只读文本
- 类型是
&str
,只是“借来读一下” - 你不能修改它、不能拿来做主
所以,Option<String>
不能让你装一个“借来的只读文字进去”,因为它要能负责到底(也就是拥有它)!
✅ 正确写法(获得堆上的可变拥有字符串):
let name = Some("Tom".to_string());
let name2 = Some(String::from("Tom"));
📦 比喻理解:“借书” VS “买书”
&str
:你去图书馆借一本书看(你不能撕、不能写、不能带回家)String
:你自己买了一本书(你可以改写,放哪都行)
当你说 Option<String>
,就像你要一个“书架(Option)”去“收纳(拥有)”一本书(String),你当然不能用“借来的图书馆书”放进去!
✅ 最后总结
概念 | 通俗解释 | 是否有所有权 |
---|---|---|
if 表达式 |
判断并返回值 | ✅ 是表达式 |
loop / while / for |
循环多种方式 | ✅ 都是表达式 |
match |
多分支匹配工具 | ✅ 必须穷尽或 _ |
_ 通配符 |
兜底匹配所有其他情况 | ✅ 通用,必须覆盖全部 |
if let |
只匹配一种情况的简写 | ✅ 比 match 更简洁 |
Option<T> |
表示“值可能不存在” | ✅ 替代 null |
Some(x) |
有值的情况 | ✅ x 必须符合类型 |
None |
没值的情况 | ✅ 代表空值 |
"abc" (&str ) |
借来的不可变引用 | ❌ 无所有权 |
"abc".to_string() / String::from("abc") |
堆上有所有权的可变字符串 | ✅ 有所有权 |
🎁 Bonus:一句话记住核心概念
“如果你要拥有,就别拿别人的,Rust 会让你自己造一份!”
这就是 Rust 的哲学:安全、清晰、必须负责任。