Skip to content

实战总结

> 综合运用本章函数知识,通过实战示例巩固函数定义、参数传递和闭包使用。

调试技巧

使用 dbg! 调试函数

rust
fn calculate(x: i32, y: i32) -> i32 {
    let sum = dbg!(x + y);
    let product = dbg!(x * y);
    let result = sum + product;
    dbg!(result)
}

fn main() {
    let r = calculate(3, 5);
    println!("最终结果:{}", r);
}
▶ Run

输出:

[src/main.rs:3] x + y = 8
[src/main.rs:4] x * y = 15
[src/main.rs:5] result = 23
最终结果:23

打印函数签名

rust
fn my_function(x: i32, y: String) -> (i32, String) {
    (x, y)
}

fn main() {
    // 打印类型信息
    println!("函数类型:{:?}", std::any::type_name_of_val(&my_function));
}
▶ Run

常见错误

错误 1:忘记返回类型

rust
// ❌ 错误:有返回值但没声明返回类型
// fn add(x: i32, y: i32) {
//     x + y
// }

// ✅ 正确
fn add(x: i32, y: i32) -> i32 {
    x + y
}
▶ Run

错误信息:

error[E0308]: mismatched types
 --> src/main.rs:3:1
  |
2 | fn add(x: i32, y: i32) {  // 隐含返回 ()
  |                        - help: add `-> i32` to return the type
3 |     x + y
  |     ^^^^^ expected `()`, found `i32`

错误 2:语句和表达式混淆

rust
// ❌ 错误:分号让表达式变成语句
// fn add(x: i32, y: i32) -> i32 {
//     let result = x + y;  // 分号,语句
// }  // 返回 () 而不是 i32

// ✅ 正确
fn add(x: i32, y: i32) -> i32 {
    let result = x + y;  // 语句
    result  // 表达式,返回值
}
▶ Run

错误信息:

error[E0308]: mismatched types
 --> src/main.rs:4:1
  |
2 | fn add(x: i32, y: i32) -> i32 {
  |                         --- expected `i32` because of return type
3 |     let result = x + y;
4 | }
  | ^^^^^ expected `i32`, found `()`

错误 3:所有权问题

rust
fn take_string(s: String) {
    println!("{}", s);
}

fn main() {
    let s = String::from("hello");
    take_string(s);
    // println!("{}", s);  // ❌ 错误:s 已被移动
}
▶ Run

错误信息:

error[E0382]: borrow of moved value: `s`
 --> src/main.rs:6:20
  |
5 |     let s = String::from("hello");
  |         - move occurs because `s` has type `String`
6 |     take_string(s);
  |                 - value moved here
7 |     println!("{}", s);  // ❌ 错误
  |                    ^ value borrowed here after move

修复:

rust
// 方法 1:传递引用
fn take_string(s: &String) {
    println!("{}", s);
}

// 方法 2:传递&str(更佳)
fn take_string(s: &str) {
    println!("{}", s);
}

// 方法 3:返回所有权
fn take_string(s: String) -> String {
    println!("{}", s);
    s
}
▶ Run

错误 4:参数类型不匹配

rust
fn print_name(name: &str) {
    println!("{}", name);
}

fn main() {
    let name = String::from("Alice");
    // print_name(name);  // ❌ 类型不匹配
    print_name(&name);  // ✅ 传递引用
}
▶ Run

练习

练习 1:数学函数

实现以下函数:

  1. is_prime(n: u32) -> bool - 判断是否为质数
  2. gcd(a: u32, b: u32) -> u32 - 计算最大公约数
  3. fibonacci(n: u32) -> u32 - 计算斐波那契数列第 n 项

练习 2:字符串处理

实现以下函数:

  1. reverse_string(s: &str) -> String - 反转字符串
  2. is_palindrome(s: &str) -> bool - 判断是否为回文
  3. count_vowels(s: &str) -> usize - 统计元音字母数量

练习 3:数据结构

实现一个函数,接受一个整数数组,返回一个包含以下统计信息的结构体:

  • 最小值
  • 最大值
  • 平均值
  • 中位数

小结

函数语法要点

概念语法说明
函数定义fn name(params) -> Type { body }基本结构
参数类型x: i32必须显式标注
返回类型-> i32有返回值时必须
表达式返回x + y无分号
语句返回return x + y显式返回或提前返回
单元类型()无返回值时的隐含返回

关键概念

  1. 表达式 vs 语句

    • 表达式返回值(无分号)
    • 语句执行操作(有分号)
  2. 所有权传递

    • 传递值:转移所有权
    • 传递引用:借用
  3. 参数命名

    • 使用蛇形命名(snake_case)
    • 选择有意义的名字

最佳实践

  1. 函数应该短小,只做一件事
  2. 函数名应该清楚表达其功能
  3. 优先使用 &str 而不是 &String
  4. 使用 OptionResult 处理可能的失败
  5. 写文档注释说明函数的用途

第 06 章:控制流

练习题

详见:练习题