当前位置: 首页 > article >正文

Rust从入门到精通之入门篇:6.函数

函数

在本章中,我们将学习 Rust 中的函数定义和使用。函数是 Rust 程序的基本构建块,它允许我们将代码组织成可重用的块,提高代码的可读性和可维护性。

函数定义

Rust 中使用 fn 关键字定义函数。函数名遵循 Rust 的命名约定,使用蛇形命名法(snake_case)。

fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("这是另一个函数。");
}

在上面的例子中,我们定义了两个函数:mainanother_functionmain 函数是程序的入口点,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
}

练习题

  1. 编写一个函数 is_palindrome,接受一个字符串参数,判断它是否是回文(正着读和倒着读一样)。

  2. 编写一个函数 fibonacci,接受一个整数 n,返回斐波那契数列的第 n 个数。

  3. 编写一个高阶函数 transform_array,接受一个整数数组和一个函数作为参数,对数组中的每个元素应用该函数,并返回结果数组。

  4. 编写一个函数 calculate_average,接受一个整数数组,返回其平均值。

  5. 编写一个闭包,用于过滤出数组中的所有偶数,并使用它来处理一个整数数组。

总结

在本章中,我们学习了:

  • 如何定义和调用函数
  • 函数参数和返回值的声明
  • 语句和表达式的区别
  • 如何使用闭包
  • 高阶函数的概念和用法

函数是 Rust 程序的基本构建块,掌握函数的定义和使用对于编写清晰、模块化的代码至关重要。在下一章中,我们将学习 Rust 中的注释和文档,这对于代码的可读性和可维护性同样重要。


http://www.kler.cn/a/610522.html

相关文章:

  • SpringBoot中安全的设置阿里云日志SLS的accessKey
  • 26考研——栈、队列和数组_栈(3)
  • 三维空间中点、线、面的关系
  • 详细介绍Qt中用于断言的宏 Q_ASSERT
  • k8s存储介绍(五)PV与PVC
  • 【Rust】使用 Rust 语言实践完整的 TDD(测试驱动开发)流程
  • RK3568 驱动和设备匹配的几种方法
  • STM32F103_LL库+寄存器学习笔记04 - GPIO设置输出模式
  • 6.4考研408数据结构图论核心知识点深度解析
  • 《Oracle DBA入门实战:十大高频问题详解与避坑指南》
  • 卷积神经网络 - AlexNet
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例3,TableView16_03 拖拽视觉反馈示例
  • [算法笔记]一段数量变化的无序区间的中位数查找--双堆法
  • 【区块链安全 | 第六篇】NFT概念详解
  • 最大字段和问题 C++(穷举、分治法、动态规划)
  • 构建稳健的机器学习系统:应对数据偏移挑战
  • 使用ros_gz_bridge将gz topic转换成ros2 topic
  • 数据库——MySQL基础操作
  • 文件上传绕过的小点总结(5)
  • 使用 Chromedp 监听网页请求和响应