函数基础
> 掌握 Rust 函数的定义语法,理解为什么 Rust 要求函数参数必须标注类型。
为什么需要函数?
函数的作用
想象你在组装家具:
没有函数:
┌─────────────────────────────────────────┐
│ 1. 拿螺丝刀 │
│ 2. 拿起螺丝 │
│ 3. 拧螺丝...重复 100 次 │
│ 4. 拿锤子 │
│ 5. 敲钉子...重复 50 次 │
│ ...代码重复,难以维护... │
└─────────────────────────────────────────┘
有函数:
┌─────────────────────────────────────────┐
│ fn 拧螺丝 (螺丝,位置) { ... } │
│ fn 敲钉子 (钉子,位置) { ... } │
│ │
│ fn 组装 () { │
│ 拧螺丝 (螺丝 1, 位置 A); │
│ 敲钉子 (钉子 1, 位置 B); │
│ } │
│ │
│ → 代码复用,易于理解和维护 │
└─────────────────────────────────────────┘函数的优势
| 优势 | 说明 |
|---|---|
| 代码复用 | 写一次,用多次 |
| 模块化 | 将大问题分解为小问题 |
| 抽象 | 隐藏实现细节,只暴露接口 |
| 可测试 | 独立测试每个函数 |
| 可维护 | 修改一处,影响全局 |
函数定义基础
完整语法
rust
▶ Run// 函数定义的完整结构
fn function_name(param1: Type1, param2: Type2) -> ReturnType {
// 函数体
// 最后一行表达式作为返回值(如果返回类型不是 ())
expression
}各部分详解
rust
▶ Run// 函数名 参数列表 返回类型 函数体
// ↓ ↓ ↓ ↓
fn add (x: i32, y: i32) -> i32 { x + y }
│ │ │ │ │
│ │ │ │ └─ 函数实现
│ │ │ └─ 告诉编译器返回什么类型
│ │ └─ 参数名:类型(Rust 参数必须标注类型)
│ └─ 函数名(蛇形命名:小写字母 + 下划线)
└─ fn 是 function 的缩写示例:打招呼函数
rust
▶ Runfn main() {
// 调用函数
greet();
greet();
greet();
}
// 函数定义
fn greet() {
println!("你好,世界!");
}输出:
你好,世界!
你好,世界!
你好,世界!语言对比:函数定义
Rust vs 其他语言
┌─────────────────────────────────────────────────────┐
│ 函数定义对比 │
├─────────────────────────────────────────────────────┤
│ │
│ Python: │
│ ├── def add(x, y): # 无类型标注 │
│ │ return x + y │
│ ├── 优点:简洁 │
│ ├── 缺点:类型错误在运行时发现 │
│ │
│ JavaScript: │
│ ├── function add(x, y) { # 无类型标注 │
│ │ return x + y; │
│ ├── } │
│ ├── 或箭头函数: │
│ │ const add = (x, y) => x + y; │
│ ├── 优点:灵活 │
│ ├── 缺点:类型不可预测 │
│ │
│ Java: │
│ ├── public int add(int x, int y) { // 显式类型 │
│ │ return x + y; │
│ ├── } │
│ ├── 优点:类型安全 │
│ ├── 缺点:语法冗长 │
│ │
│ Rust: │
│ ├── fn add(x: i32, y: i32) -> i32 { │
│ │ x + y │
│ ├── } │
│ ├── 优点: │
│ │ • 类型安全(编译时检查) │
│ │ • 简洁(无需 return 关键字) │
│ │ • 表达式返回(最后一行自动返回) │
│ ├── 特点:参数必须标注类型 │
│ │
│ 对比结论: │
│ ├── Python/JS:灵活但不安全 │
│ ├── Java:安全但冗长 │
│ ├── Rust:安全且简洁 │
│ │
└─────────────────────────────────────────────────────┘实际代码对比
rust
▶ Run// Rust:简洁且安全
fn add(x: i32, y: i32) -> i32 {
x + y // 无需 return,最后一行自动返回
}python
# Python:简洁但不安全
def add(x, y):
return x + y # 类型错误在运行时发现
# add("hello", 5) → 运行时 TypeErrorjava
// Java:安全但冗长
public int add(int x, int y) {
return x + y; // 必须显式 return
}Rust 简洁性优势
rust
▶ Run// Rust 无需 return 关键字
fn square(x: i32) -> i32 {
x * x // 表达式自动返回
}
// 等价于其他语言的显式 return
fn square_verbose(x: i32) -> i32 {
return x * x; // 也可以写 return,但不推荐
}常见错误诊断
错误 1:参数缺少类型标注
错误代码
rust
▶ Runfn add(x, y) {
x + y
}编译器错误
error[E0416]: expected type, found `x`
--> src/main.rs:1:8
|
1 | fn add(x, y) {
| ^ expected type
|
help: function parameters must have a type annotation
|
1 | fn add(x: <type>, y: <type>) {解读错误信息
┌─────────────────────────────────────────────────────┐
│ 错误信息解读 │
├─────────────────────────────────────────────────────┤
│ │
│ error[E0416]: expected type, found `x` │
│ │ │
│ │ 错误码 E0416 = "期望类型,发现变量名" │
│ │ 参数缺少类型标注 │
│ │
│ help: function parameters must have a type │
│ annotation │
│ │ │
│ │ 说明:函数参数必须有类型标注 │
│ │ 建议:添加类型 x: <type> │
│ │
│ Rust 规则: │
│ • 参数必须标注类型 │
│ • 返回类型可推断,但参数不能 │
│ │
└─────────────────────────────────────────────────────┘修复方案
rust
▶ Run// ✅ 正确:添加类型标注
fn add(x: i32, y: i32) -> i32 {
x + y
}错误 2:返回类型不匹配
错误代码
rust
▶ Runfn get_number() -> i32 {
"hello" // 返回字符串,但声明返回 i32
}编译器错误
error[E0308]: mismatched types
--> src/main.rs:2:5
|
1 | fn get_number() -> i32 {
| --- expected `i32` because of return type
2 | "hello"
| ^^^^^^^ expected `i32`, found `&str`解读与修复
错误码 E0308:类型不匹配
原因:
├── 返回类型声明:i32
├── 实际返回值:&str
├── 类型不兼容
修复:
├── 方案 1:修改返回值
│ fn get_number() -> i32 {
│ 42
│ }
│
├── 方案 2:修改返回类型
│ fn get_number() -> &'static str {
│ "hello"
│ }错误 3:忘记返回值
错误代码
rust
▶ Runfn add(x: i32, y: i32) -> i32 {
x + y; // 分号使其变成语句,无返回值
}编译器错误
error[E0308]: mismatched types
--> src/main.rs:1:29
|
1 | fn add(x: i32, y: i32) -> i32 {
| ^^^ expected `i32` because of return type
2 | x + y;
| - help: remove this semicolon to return this value
|
= note: expected type `i32`
found unit type `()`解读错误信息
┌─────────────────────────────────────────────────────┐
│ 错误信息解读 │
├─────────────────────────────────────────────────────┤
│ │
│ expected `i32`, found unit type `()` │
│ │ │
│ │ 说明:期望返回 i32,实际返回 ()(空元组) │
│ │ 原因:分号使表达式变成语句 │
│ │
│ help: remove this semicolon to return this value │
│ │ │
│ │ 建议:删除分号,使其成为表达式 │
│ │ 解决方案:x + y(无分号) │
│ │
│ Rust 规则: │
│ • 表达式 + 分号 = 语句(无返回值) │
│ • 表达式无分号 = 表达式(有返回值) │
│ │
│ 例: │
│ • x + y; → 语句,返回 () │
│ • x + y → 表达式,返回 i32 │
│ │
└─────────────────────────────────────────────────────┘修复方案
rust
▶ Run// ✅ 正确:删除分号
fn add(x: i32, y: i32) -> i32 {
x + y // 无分号,表达式返回
}
// 或显式 return(不推荐)
fn add(x: i32, y: i32) -> i32 {
return x + y;
}错误诊断速查
| 错误码 | 错误类型 | 原因 | 快速解决 |
|---|---|---|---|
| E0416 | 参数缺少类型 | 参数未标注类型 | 添加 : Type |
| E0308 | 返回类型不匹配 | 返回值类型错误 | 修正返回值或类型 |
| 分号错误 | 返回空元组 | 表达式后有分号 | 删除分号 |
小结
本章核心:
- Rust 函数简洁且安全
- 参数必须标注类型
- 最后一行表达式自动返回
- 分号区别语句和表达式
- 编译器错误是最好的学习线索
练习题
详见:练习题