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

rust学习笔记14-函数

rust函数在前边已经接触很多了,现在做全面总结

1.函数定义

在 Rust 中,使用 fn 关键字来定义函数。函数可以有参数、返回值,并且可以包含任意数量的语句。

fn function_name(parameter_list) -> ReturnType {
    // 函数体
    // 返回值(可选)
}

2.返回值
Rust 函数的返回值类型需要显式声明。如果函数没有返回值,则返回类型为 (),即单元类型。

隐式返回:如果函数的最后一行表达式没有分号,它将被视为返回值。
显式返回:使用 return 关键字返回一个值。

// 隐式返回
fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 显式返回
fn subtract(a: i32, b: i32) -> i32 {
    return a - b;
}

fn main() {
    let sum = add(5, 3);
    let difference = subtract(5, 3);

    println!("Sum: {}, Difference: {}", sum, difference);
}

3.函数参数

(1)函数值参数传递(Move)
        函数的代码本身通常是存储在可执行文件的代码段,而在调用时函数会在栈上开辟一个新的stack frame(栈空间),用于存储函数的局部变量、参数和返回地址等信息,而当函数结束后会释放该空间。
        而当传入non-Copy value(Vec、String等)传入函数时实参会转移value的所有权给形参,实参会失去value的所有权而在函数结束时,value的所有权会释放

(2)不可变借用

        如果你不想失去value的所有权,你又没有修改value的需求,你可以使用不可变借用
        在 Rust 中,你可以将不可变引用作为函数的参数,从而在函数内部访问参数值但不能修改它。这有助于确保数据的安全性,防止在多处同时对数据进行写操作,从而避免数据竞争。
        如何应用不可变借用,通过Use * to deference,去获取其的值

fn borrow_test(s: &String){
    println!("{}", (*s).to_uppercase());

}
fn main() {
    let b = String::from("rust");
    borrow_test(&b);
    println!("{}", b);

(3)可变借用

        如何你有修改值的需求你可以使用可变借用,以允许在函数内部修改参数的值。以允许在函数内部修改参数的值。但在同一时间内只能有一个可变引用。
        需要再形参前加&mut

        如何应用可变借用,还是通过Use * to deference,去获取其的值

fn increment_by_reference(x: &mut i32) {
    *x += 1; // 修改引用指向的值
}

fn main() {
    let mut num = 5;
    increment_by_reference(&mut num);
    println!("{}", num); // 输出:6
}

4.递归函数

递归函数通常包含两个主要部分:

        基准条件(Base Case):递归终止的条件,避免无限递归。

        递归步骤(Recursive Step):将问题分解为更小的子问题,并调用自身来解决这些子问题。

//阶乘递归
fn factorial(n: u32) -> u32 {
    if n == 0 {
        1 // 基准条件
    } else {
        n * factorial(n - 1) // 递归步骤
    }
}

fn main() {
    let result = factorial(5);
    println!("5的阶乘:{}", result);
}

5.生命周期与函数

        在 Rust 中,生命周期(lifetimes)是一种编译时检查机制,用于确保引用始终有效。Rust 编译器使用生命周期注解来验证引用不会超出其指向的数据的有效范围,从而避免悬垂指针和其他内存安全问题。理解生命周期的概念和用法是编写安全且高效的 Rust 代码的关键。

为什么需要生命周期?
Rust 的所有权系统确保每个值都有一个明确的所有者,并且当所有者离开作用域时,该值会被自动释放。然而,当涉及到引用时,编译器需要一种方法来确保引用在其所指向的数据被释放之前保持有效。这就是生命周期的作用。 

生命周期的基本概念
生命周期是一个抽象的概念,表示引用的有效范围。生命周期注解通过撇号 'a 来表示,其中 'a 是一个标识符,可以是任意的,但通常使用 'a, 'b, 'c 等。

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

生命周期省略规则
Rust 编译器有一些内置的生命周期省略规则,允许在某些情况下省略显式的生命周期注解。这些规则适用于简单的情况,使代码更加简洁。

编译器在没有显式注解的情况下,使用三个规则来推断这些生命周期
第一个规则是每个作为引用的参数都会得到它自己的生命周期参数。
第二个规则是,如果只有一个输入生命周期参数,那么该生命周期将被分配给所有输出生命周期参数(该生命周期将分配给返回值)
第三个规则是,如果有多个输入生命周期参数,但其中一个是对 self 或不可变 self 的引用时。因为在这种情况下它是一个方法,所以 self 的生命周期被分配给所有输出生命参数

//规则一 每个引用参数都有其自己的生命周期 foo等价foo2
fn foo(x: &i32) -> &i32 { x }
fn foo2<'a>(x: &'a i32) -> &'a i32 { x }

//规则二 如果只有一个输入引用,则输出引用与该输入引用具有相同的生命周期
fn first_word(s: &str) -> &str {
    // 假设这是一个实现
    "example"
}

//规则三 如果有多个输入引用,则第一个输入引用决定输出引用的生命周期
//这个函数会导致编译错误,因为编译器无法确定返回值的生命周期应该与 x 还是 y 相同。因此,需要显式地添加生命周期注解:如longest2
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}
fn longest2(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}

总结,函数是每个编程语言最重要内容,在rust中,函数参数分所有权移动(Move)、不可变引用、可变引用需要重点理解掌握。生命周期 是 Rust 编译器用来确保引用在其所指向的数据被释放之前保持有效的机制。生命周期注解 使用撇号 'a 表示,帮助编译器验证引用的有效性。

相关文章:

  • SSO单点登录
  • FLASK和GPU依赖安装
  • Ollama+OpenManus详细部署实战
  • 【SegRNN 源码理解】验证集和测试集
  • C语言【内存函数】详解加模拟实现
  • 大模型最新面试题系列:微调篇之微调框架(一)
  • 78. Harmonyos NEXT 懒加载数据源实现解析:BasicDataSource与CommonLazyDataSourceModel详解
  • 背诵--2
  • 【商城实战(33)】解锁版本迭代与更新策略
  • 敏捷开发在中小团队中的应用与挑战:实战指南与避坑手册
  • 对Spring的每种事务传播级别的应用场景和失效场景
  • 20250315在windows10下开热点步骤
  • linux系统CentOS 7版本搭建NFS共享存储
  • 为什么HashMap 头插法会造成死锁
  • JDBC 核心 API 全面解析与高效数据库操作
  • 如何用正则表达式爬取古诗文网中的数据(python爬虫)
  • K8S下nodelocaldns crash问题导致域名请求响应缓慢
  • 基于Python+Flask+MySQL+HTML的爬取豆瓣电影top-250数据并进行可视化的数据可视化平台
  • 睡不着运动锻炼贴士
  • 工程化与框架系列(34)--前端重构技巧指南
  • 广西:坚决拥护党中央对蓝天立进行审查调查的决定
  • 贵州仁怀通报“正新鸡排鸡腿里全是蛆”:已对同类产品封存送检
  • 中方是否计划解除或调整稀土出口管制?外交部回应
  • 泉州围头湾一港区项目炸礁被指影响中华白海豚,官方:已叫停重新评估
  • 雷军内部演讲回应质疑:在不服输、打不倒方面,没人比我们更有耐心
  • 视频丨中国海警成功救助8名外籍遇险渔民,韩方向中方致谢