函数
在本章中,我们将学习 Rust 中的函数定义和使用。函数是 Rust 程序的基本构建块,它允许我们将代码组织成可重用的块,提高代码的可读性和可维护性。
函数定义
Rust 中使用 fn
关键字定义函数。函数名遵循 Rust 的命名约定,使用蛇形命名法(snake_case)。
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("这是另一个函数。");
}
在上面的例子中,我们定义了两个函数:main
和 another_function
。main
函数是程序的入口点,another_function
是我们自定义的函数。
函数参数
函数可以接受参数,这些参数是传递给函数的值。在函数签名中,必须声明每个参数的类型。
fn main() {
print_number(5);
print_labeled_measurement(5, 'h');
}
fn print_number(x: i32) {
println!("x 的值是: {}", x);
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("测量值是: {}{}", value, unit_label);
}
在这个例子中,print_number
函数接受一个 i32
类型的参数,print_labeled_measurement
函数接受一个 i32
类型和一个 char
类型的参数。
函数体中的语句和表达式
Rust 是一种基于表达式的语言。语句是执行操作但不返回值的指令,而表达式则是计算并产生一个值。
fn main() {
let y = 6; // 语句
let x = 5; // 语句
// 表达式
let y = {
let x = 3;
x + 1 // 注意这里没有分号,这是一个表达式
};
println!("y 的值是: {}", y); // 输出:y 的值是: 4
}
在上面的例子中,代码块 { let x = 3; x + 1 }
是一个表达式,它计算并返回一个值。注意,表达式的最后一行没有分号,因为它是要返回的值。如果在表达式的末尾添加分号,它就变成了一个语句,不会返回值。
带返回值的函数
函数可以向调用它的代码返回值。我们在箭头(->
)后面声明返回值的类型,但不对返回值命名。
fn five() -> i32 {
5 // 返回值,注意没有分号
}
fn main() {
let x = five();
println!("x 的值是: {}", x);
}
在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。也可以使用 return
关键字提前从函数返回,但大多数函数隐式地返回最后一个表达式。
fn plus_one(x: i32) -> i32 {
x + 1 // 返回 x + 1 的值
}
fn main() {
let x = plus_one(5);
println!("x 的值是: {}", x); // 输出:x 的值是: 6
}
如果在表达式后面加上分号,它就变成了语句,不会返回值:
fn plus_one(x: i32) -> i32 {
x + 1; // 错误:此函数的块不返回值
}
注释函数
可以使用文档注释来为函数提供文档:
/// 将输入值加一并返回
///
/// # Examples
///
/// ```
/// let five = 5;
/// let six = plus_one(5);
/// assert_eq!(6, six);
/// ```
fn plus_one(x: i32) -> i32 {
x + 1
}
函数重载
Rust 不支持函数重载(即同名但参数不同的多个函数)。每个函数名在其作用域内必须是唯一的。
闭包
Rust 有一种类似于函数的特性,称为闭包(closures)。闭包是可以保存在变量中或作为参数传递给其他函数的匿名函数。
fn main() {
let add_one = |x: i32| -> i32 { x + 1 };
let five = 5;
println!("{}+1={}", five, add_one(five));
}
闭包可以捕获其环境中的值:
fn main() {
let x = 4;
let equal_to_x = |z| z == x;
let y = 4;
assert!(equal_to_x(y));
}
高阶函数
Rust 支持高阶函数,即接受函数作为参数或返回函数的函数。
fn apply_twice<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32,
{
f(f(x))
}
fn main() {
let add_one = |x| x + 1;
let result = apply_twice(add_one, 5);
println!("结果是: {}", result); // 输出:结果是: 7
}
示例程序
让我们编写一个程序,展示 Rust 中函数的各种用法:
fn main() {
// 调用无参数函数
say_hello();
// 调用带参数的函数
greet("Alice");
// 调用多参数函数
let sum = add(5, 7);
println!("5 + 7 = {}", sum);
// 使用函数返回值
let result = calculate_rectangle_area(4.5, 6.2);
println!("矩形面积: {}", result);
// 使用表达式作为函数体
let squared = square(3);
println!("3 的平方是: {}", squared);
// 使用闭包
let is_even = |n: i32| n % 2 == 0;
for i in 1..=5 {
println!("{} 是偶数: {}", i, is_even(i));
}
// 使用高阶函数
let numbers = [1, 2, 3, 4, 5];
let sum: i32 = numbers.iter().map(|&x| x * 2).sum();
println!("数组中所有元素乘以 2 后的总和: {}", sum);
}
// 无参数函数
fn say_hello() {
println!("Hello!");
}
// 带一个参数的函数
fn greet(name: &str) {
println!("你好, {}!", name);
}
// 带两个参数的函数
fn add(a: i32, b: i32) -> i32 {
a + b // 返回 a + b 的值
}
// 带两个浮点参数的函数
fn calculate_rectangle_area(width: f64, height: f64) -> f64 {
width * height
}
// 使用表达式作为函数体
fn square(n: i32) -> i32 {
n * n
}
练习题
-
编写一个函数
is_palindrome
,接受一个字符串参数,判断它是否是回文(正着读和倒着读一样)。 -
编写一个函数
fibonacci
,接受一个整数 n,返回斐波那契数列的第 n 个数。 -
编写一个高阶函数
transform_array
,接受一个整数数组和一个函数作为参数,对数组中的每个元素应用该函数,并返回结果数组。 -
编写一个函数
calculate_average
,接受一个整数数组,返回其平均值。 -
编写一个闭包,用于过滤出数组中的所有偶数,并使用它来处理一个整数数组。
总结
在本章中,我们学习了:
- 如何定义和调用函数
- 函数参数和返回值的声明
- 语句和表达式的区别
- 如何使用闭包
- 高阶函数的概念和用法
函数是 Rust 程序的基本构建块,掌握函数的定义和使用对于编写清晰、模块化的代码至关重要。在下一章中,我们将学习 Rust 中的注释和文档,这对于代码的可读性和可维护性同样重要。