杂谈函数式

函数式编程

  • 函数是编程传承自数学,通过函数抽象和应用的机制,能表示各种复杂的计算过程。任何可计算函数都可以用 lambda 表达式来表示,它能对函数进行定义、组合和嵌套,实现各种逻辑和算法。

不可变

  • 严格意义上讲,函数式的输入和输出是固定的,且不修改外部状态,什么意思呢?。
int a=1;
int multiple(int a,int b){
 return a*b
}
multiple(a,2) 
  • 现在我们要修改a的值,传承自函数式思想要求我们
a=multiple(a,2) 
//而非
void multiple(int *a, int b) {
    *a = *a * b; //修改外部状态
}
  • 可能这里有点不太好理解。那我们联系下实际,setSate是个什么样的函数呢?
  • 同时提个问,为什么lambda表达式是不可变的思想呢?

为什么要有不可变

展开查看

点击展开答案...

函数式的核心是函数的组合

臭名昭著的链式调用

  • 令人诟病?的rust链式调用
    let result = (0..20)                         // 生成范围 0..19
        .filter(|x| x % 3 != 0)                  // 过滤3的倍数
        .map(|x| x * 2)                          // 翻倍
        .filter_map(|x| if x > 10 { Some(x) } else { None }) // 过滤<=10的数
        .enumerate()                             // 添加索引
        .map(|(i, x)| (i as i32 + x, x % 5))     // 元组映射:(索引+x, x%5)
        .filter(|(sum, mod5)| sum % 2 == 0 && *mod5 != 0) // 过滤条件
        .flat_map(|(sum, mod5)| vec![sum, mod5, sum * mod5]) // 展开为向量
        .collect::<Vec<_>>()                     // 收集到Vec
        .windows(2)                              // 滑动窗口
        .map(|pair| pair[0] * pair[1])           // 相邻元素相乘
        .chain([42, 99].into_iter())             // 连接额外元素
        .skip(2)                                 // 跳过前两个元素
        .take(5)                                 // 取前5个元素
        .fold(1, |acc, x| acc * x); 

地狱般的嵌套调用

  • 著名的回调地狱
simulateAjaxRequest('https://example.com/api1', (ajaxData1) => {
  processData(ajaxData1, (processedData1) => {
    simulateAjaxRequest('https://example.com/api2', (ajaxData2) => {
      processData(ajaxData2, (processedData2) => {
        validateData(processedData2, (validData2) => {
          if (validData2) {
            simulateAjaxRequest('https://example.com/api3', (ajaxData3) => {
              processData(ajaxData3, (processedData3) => {
                validateData(processedData3, (validData3) => {
                  if (validData3) {
                    console.log('所有操作完成,最终数据:', validData3);
                  } else {
                    console.log('最终数据验证失败');
                  }
                });
              });
            });
          } else {
            console.log('数据处理或验证失败,操作中断');
          }
        });
      });
    });
  });
});
  • 虽然上面这些代码对我们的可读性造成了很大的负担,但是也可以从中瞥见函数式编程的强大能力。力扣中的一行代码解决问题也无一不是函数式编程的体现。
  • 但是毕竟函数式编程上手难度还是比较高的,谨慎使用1

Footnotes

  1. 小tips,思考函数定义时,优先确定返回值,其次确定输入值。可以有效帮助我们定义函数。

For Paul

这是一个个人博客,主要用于记录自己的学习过程,用于技术交流

© 2025 Paul Blog • Made withby Paul

使用 Next Rust 和 Tailwind CSS 构建

最近更新时间: 2025-07-01