函数与控制流:让代码学会“思考”和“重复”
各位同学,今天我们来聊聊 Rust 里最核心的两个基本功——函数和控制流。说白了,函数就是给代码块起个名字,方便反复调用;控制流就是让代码根据条件走不同的路,或者重复执行某段逻辑。这两样东西掌握好了,你就能写出有“脑子”的程序。
函数定义与参数
Rust 的函数用 fn 关键字声明。我个人习惯把函数名写成蛇形命名法(snake_case),比如 calculate_area。参数必须写明类型,这一点和 TypeScript 有点像,但 Rust 更严格——它不允许类型推断发生在函数签名里。
fn greet(name: &str) {
println!("你好,{}!", name);
}
嗯,这里要注意:&str 是字符串切片,它不会拿走数据的所有权。我在项目中遇到过新手直接把 String 传进去,结果函数用完之后原变量就不能用了——这就是所有权转移的坑。
语句与表达式
Rust 里有个很重要的区分:语句(statement)和表达式(expression)。语句执行动作,不返回值;表达式计算值,可以返回。你想想看,这其实很像自然语言里的“祈使句”和“疑问句”。
let x = 5; // 语句
let y = { // 代码块是表达式
let a = 3;
a + 2 // 没有分号,这就是返回值
};
我曾经在写复杂逻辑时,忘记在代码块末尾加分号,结果编译器报错说类型不匹配。后来我养成了习惯:想返回就省略分号,不想返回就加分号。这个规则简单粗暴,但很管用。
核心要点:Rust 中几乎所有东西都是表达式,包括 if 和 match。这意味着你可以把条件判断的结果直接赋值给变量。
返回值
函数返回值用 -> 箭头指定类型。最后一个表达式的值就是返回值,也可以用 return 提前返回。我个人更倾向于用隐式返回,除非需要提前退出。
fn add(a: i32, b: i32) -> i32 {
a + b // 隐式返回
}
fn early_return(x: i32) -> i32 {
if x < 0 {
return 0; // 提前返回
}
x * 2
}
我记得有一次写递归函数,忘记写返回类型,编译器直接报错。Rust 在这方面很严格——所有函数都必须显式声明返回类型,除了 ()(单元类型)可以省略。
if/else 分支
Rust 的 if 条件不需要括号,但必须用花括号。这一点和 Go 很像。而且 if 本身是表达式,可以返回值。
let score = 85;
let grade = if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else {
"C"
};
这里有个坑:所有分支返回的类型必须一致。我曾经在项目中写了一个 if 表达式,一个分支返回整数,另一个返回字符串,编译器直接拒绝编译。嗯,这其实是好事——它逼着你写出类型安全的代码。
避坑指南:我曾经在 if 表达式里忘记在最后加分号,导致整个表达式被当作语句处理,变量赋值失败。记住:if 作为表达式使用时,整个语句末尾必须加分号。
循环:loop、while、for
Rust 提供了三种循环方式,各有各的适用场景。
loop:无限循环
loop 会一直执行,直到你主动 break。它也可以返回值,这个特性很实用。
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 返回 20
}
};
我个人习惯用 loop 做事件循环或重试逻辑。比如网络请求失败时,用 loop 配合 break 实现最多重试三次的逻辑。
while:条件循环
while 在条件为真时反复执行。它比 loop 更安全,因为至少有个退出条件。
let mut n = 3;
while n > 0 {
println!("{}!", n);
n -= 1;
}
你想想看,while 其实等价于 loop 加 if 判断。但 while 更简洁,语义也更清晰。
for:遍历循环
for 是 Rust 里最常用的循环方式,用来遍历迭代器。它比 C 风格的 for (i=0; i<n; i++) 更安全,不会出现越界问题。
let arr = [10, 20, 30];
for element in arr.iter() {
println!("值: {}", element);
}
// 范围语法
for i in 0..5 {
println!("{}", i); // 输出 0 到 4
}
我在项目中几乎只用 for 循环,除非需要无限循环或条件循环。它配合迭代器可以写出非常优雅的代码。
break 与 continue
break 跳出整个循环,continue 跳过当前迭代进入下一次。这两个关键字在嵌套循环中特别有用,可以配合标签使用。
'outer: for i in 0..5 {
for j in 0..5 {
if i * j > 10 {
break 'outer; // 跳出外层循环
}
println!("({}, {})", i, j);
}
}
我曾经在解析嵌套数据结构时,用标签 break 直接跳出多层循环,代码瞬间变得清晰。没有标签的话,你得用 flag 变量,那代码就丑了。
小技巧:break 后面可以跟表达式,用于从 loop 返回值。但 while 和 for 不支持这个特性,只有 loop 可以。
知识体系图
下面这张图帮你理清函数与控制流的核心脉络:
这张图把函数和控制流分成了两大块,中间用虚线连接——因为函数体里必然包含控制流,而控制流也经常调用函数。底部的循环控制是两者的交叉点,break 和 continue 在循环中扮演着“交通警察”的角色。
实战建议
学到这里,你应该能写出带逻辑判断和循环的 Rust 程序了。我个人建议你从一个小练习开始:写一个猜数字游戏,用 loop 实现游戏循环,用 if/else 判断猜大猜小,用 break 在猜对时退出。这个练习几乎涵盖了今天讲的所有知识点。
记住:函数让代码可复用,控制流让代码有逻辑。两者结合,你就能构建出真正有用的程序。下一章我们会深入所有权和借用,那才是 Rust 真正的“硬核”部分——但有了函数和控制流的基础,你会更容易理解。