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

Rust学习(六):函数式编程

Rust学习(六):函数式编程

我们在前一篇博客中已经介绍了如何通过trait和impl实现Rust的面向对象编程,但是Rust本身实际上并不提倡通过类来解决问题。Rust推崇的是函数式编程,强调将函数作为参数值或者其他函数的返回值,将函数赋值给变量之后在继续执行。其中最重要的两个概念就是:闭包函数和迭代器。

1、闭包函数:

闭包函数是一种可以保存变量或作为参数传递给其他函数使用的匿名函数,和C++中的lambda表达式非常相似,闭包可以在一处创建,然后在不同的上下文中使用,同时闭包函数可以捕获调用者的作用域中的值:

//定义闭包函数:
|parameters| {
    cody_body;
    return_value
}

闭包函数还可以进一步简化,Rust可以自动推动闭包函数的参数类型和返回值类型,因此,闭包可以没有参数和返回值:

let is_even = |x| {
    x % 2 == 0
};

let num = 10;
println!("{num} is even {}", is_even(num));

如上面这个案例所示:使用闭包可以只将其赋值给变量,然后就像调用函数一样调用它即可(doge),同时闭包也可以使用外部变量:

let val = 2;
let add_val = |x| {x + val};
let num = 2;
let res = add_val(num);
println!("{num} + {val} = {res}");

如果大家和记得前面对所有权的描述,,那就一定会好奇:这里的闭包函数获取的到底是外部变量的所有权还是外部变量的引用?Rust为此设计了三个trait:

  • FnOnce:使用这个trait的闭包函数会获取外部变量的所有权。
  • FnMut:获取外部变量的可变引用。
  • Fn:获取外部变量的借用值。

如果需要强制将外部变量所有权转移到闭包内,那么可以使用move关键字:

let val = 2;
let add_val = move |x| {x+val};

2、迭代器:

迭代器会把集合中所有元素按照顺序一个一个传递给处理逻辑,允许对一个序列进行某些处理,并且会遍历这个序列中的每一项以决定何时结束。我们之前使用的for循环就是一个迭代器,迭代器默认实现了Iterator trait——iter(),用于返回i迭代器和next(),用于返回迭代器的下一项,他们是迭代器的核心功能!

根据迭代器迭代时是否可以修改数据,iter()方法有三个版本:

  • iter():返回只读可重入迭代器,元素类型:&T
  • iter_mut():返回可修改可重入迭代器,元素类型:&mut T
  • into_iter():返回只读不可重入迭代器,元素类型:T

可重入是指:迭代后原始数据还能使用,不可重入则代表迭代器消费了原始数据(这里可以借用python中的pop()方法,取出元素,并删除)

let nums = vec![1, 2, 3, 4, 5, 6];

//使用iter()方法:
for num in nums.iter() {
    println!("num:{num}");
}
println!("{:?}", nums);  //可以使用原数据nums

//使用iter_mut()方法:
for num in nums.iter_mut() {
    *num += 1;
}
println!("{:?}", nums);  //可以使用原数据nums

//使用into_iter()方法:
for num in nums.into_iter() {
    println!("num:{num}");
}
//for num in nums.iter() {println!("num:{num}");}  错误!nums已经被消费

消费是迭代器中的一种有趣且特殊的操作,sum, next, nth, fold等都是消费者,他们会对迭代器进行操作,得到最终值:

fn main() {
	let nums = vec![1, 2, 3, 4, 5, 6];
    let nums_iter = nums.iter();
    let total = nums_iter.sum::<i32>();
    
    let new_nums : Vec<i32> = (0..100).filter(|&n| n % 2 == 0).collect();
    
    println!("{:?}", new_nums);
    
    // 求小于等于1000的能被3或5整除的所有整数之和:
    let sum = (1..1000).filter(|n| n % 3 == 0 || n % 5 == 0).sum::<u32>();
    println!("{sum}");
}

实际上,除了函数式编程之外,还有命令式编程、声明式编程等多种编程范式。我们平时所用的面向对象编程(C++和python)和结构式编程(C)都属于命令式编程,命令式编程的主要思想是一步一步的精确的给出计算机运行程序的指令,而声明式编程(SQL)则以数据结构的形式表达变成逻辑,主要思想是告诉计算机应该做什么,而不是具体怎么做的(其实有点夸大了),函数式编程的思想和声明式编程类似,它更进一步是面向数学的抽象,旨在将计算描述为一种数学表达式求值,寻求一种输入输出的映射关系。


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

相关文章:

  • ss 命令的基本用法
  • 解决Docker环境变量的配置的通用方法
  • 揭秘AIGC下的数字时代:交互设计的隐秘力量与未来革命
  • 虚拟机上搭建达梦DSC简略步骤
  • 徒手从零搭建一套ELK日志平台
  • 探索Python编程:从入门到实践的高效指南
  • 【C++习题】6.字符串相加
  • Java 岗面试八股文及答案整理(2024最新版)
  • 【Android】Android侧如何抓取日志?
  • WPF应用程序的生命周期-笔记
  • IC脚本之perl
  • 鸿蒙NEXT开发案例:简体繁体转换器
  • 事务详解(特性)
  • GPU 硬件原理架构(一)
  • 搭建MC服务器
  • uniapp 相关的swiper的一些注意事项
  • C++设计模式行为模式———迭代器模式
  • 图形学笔记 - 4. 几何 -网格操作和阴影映射
  • 自动化测试面试技巧
  • 天润融通携手挚达科技:AI技术重塑客户服务体验
  • 面试小结(一)
  • 解决Electron拖拽窗口点击事件失效问题
  • Python CSV文档自动化操作详解
  • SqlServer 链接一个 SqlServer的链接服务器
  • 自动驾驶系列—探索自动驾驶数据管理的核心技术与平台
  • 微信小程序样式