Skip to content

函数基础

> 掌握 Rust 函数的定义语法,理解为什么 Rust 要求函数参数必须标注类型。

为什么需要函数?

函数的作用

想象你在组装家具:

没有函数:
┌─────────────────────────────────────────┐
│ 1. 拿螺丝刀                              │
│ 2. 拿起螺丝                             │
│ 3. 拧螺丝...重复 100 次                  │
│ 4. 拿锤子                               │
│ 5. 敲钉子...重复 50 次                   │
│ ...代码重复,难以维护...                 │
└─────────────────────────────────────────┘

有函数:
┌─────────────────────────────────────────┐
│ fn 拧螺丝 (螺丝,位置) { ... }          │
│ fn 敲钉子 (钉子,位置) { ... }          │
│                                         │
│ fn 组装 () {                            │
│     拧螺丝 (螺丝 1, 位置 A);             │
│     敲钉子 (钉子 1, 位置 B);             │
│ }                                       │
│                                         │
│ → 代码复用,易于理解和维护              │
└─────────────────────────────────────────┘

函数的优势

优势说明
代码复用写一次,用多次
模块化将大问题分解为小问题
抽象隐藏实现细节,只暴露接口
可测试独立测试每个函数
可维护修改一处,影响全局

函数定义基础

完整语法

rust
// 函数定义的完整结构
fn function_name(param1: Type1, param2: Type2) -> ReturnType {
    // 函数体
    // 最后一行表达式作为返回值(如果返回类型不是 ())
    expression
}
▶ Run

各部分详解

rust
//        函数名      参数列表        返回类型      函数体
//         ↓          ↓              ↓            ↓
fn         add       (x: i32, y: i32) -> i32     { x + y }
│          │         │               │           │
│          │         │               │           └─ 函数实现
│          │         │               └─ 告诉编译器返回什么类型
│          │         └─ 参数名:类型(Rust 参数必须标注类型)
│          └─ 函数名(蛇形命名:小写字母 + 下划线)
└─ fn 是 function 的缩写
▶ Run

示例:打招呼函数

rust
fn main() {
    // 调用函数
    greet();
    greet();
    greet();
}

// 函数定义
fn greet() {
    println!("你好,世界!");
}
▶ Run

输出:

你好,世界!
你好,世界!
你好,世界!

语言对比:函数定义

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
// Rust:简洁且安全
fn add(x: i32, y: i32) -> i32 {
    x + y  // 无需 return,最后一行自动返回
}
▶ Run
python
# Python:简洁但不安全
def add(x, y):
    return x + y  # 类型错误在运行时发现
# add("hello", 5)  → 运行时 TypeError
java
// Java:安全但冗长
public int add(int x, int y) {
    return x + y;  // 必须显式 return
}

Rust 简洁性优势

rust
// Rust 无需 return 关键字
fn square(x: i32) -> i32 {
    x * x  // 表达式自动返回
}

// 等价于其他语言的显式 return
fn square_verbose(x: i32) -> i32 {
    return x * x;  // 也可以写 return,但不推荐
}
▶ Run

常见错误诊断

错误 1:参数缺少类型标注

错误代码

rust
fn add(x, y) {
    x + y
}
▶ Run

编译器错误

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
// ✅ 正确:添加类型标注
fn add(x: i32, y: i32) -> i32 {
    x + y
}
▶ Run

错误 2:返回类型不匹配

错误代码

rust
fn get_number() -> i32 {
    "hello"  // 返回字符串,但声明返回 i32
}
▶ Run

编译器错误

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
fn add(x: i32, y: i32) -> i32 {
    x + y;  // 分号使其变成语句,无返回值
}
▶ Run

编译器错误

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
// ✅ 正确:删除分号
fn add(x: i32, y: i32) -> i32 {
    x + y  // 无分号,表达式返回
}

// 或显式 return(不推荐)
fn add(x: i32, y: i32) -> i32 {
    return x + y;
}
▶ Run

错误诊断速查

错误码错误类型原因快速解决
E0416参数缺少类型参数未标注类型添加 : Type
E0308返回类型不匹配返回值类型错误修正返回值或类型
分号错误返回空元组表达式后有分号删除分号

小结

本章核心:

  • Rust 函数简洁且安全
  • 参数必须标注类型
  • 最后一行表达式自动返回
  • 分号区别语句和表达式
  • 编译器错误是最好的学习线索

练习题

详见:练习题