【C++11】【函数式编程】Lambda 表达式的前世今生

函数式编程背景

越来越多的迹象表明,也许继面向对象编程之后,函数式编程会成为下一个编程的主流范式(只是有可能 Maybe)。
说到函数式编程编程就不得不说面向对象。
面向对象是把一个功能的一组操作和相关数据封装在一个对象里,即对象满天飞。函数式编程是把一个功能的一个操作和相关数据封装在一起,即函数满天飞。函数式编程比面向对象的优势就是粒度更小,生命周期更短。减少bug的有效途径就是减少变量的生命周期,缩小模块的粒度;这也可能是函数式编程能够活下来的原因之一吧。

函数式编程定义

是一种编程范型,它将计算机运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。λ演算,即lambda calculus。

函数式编程价值观

函数式编程强调程序的执行结果比执行过程更重要。关注于描述问题,而不是怎么实现,隐藏实现细节。
化繁为简。

函数式编程特性

面向对象编程有三大特性:封装、继承、多态。函数式编程存在自身特性。

  1. 纯函数(referential transparency) :函数式编程中的函数是纯函数,即不会修改任何外部状态,也不会产生副作用。纯函数只依赖于输入参数,输出结果也只与输入参数有关,因为调用函数的结果具有一致性,所以根本不需要加锁,也就不存在死锁的问题。也因此具有可重复性和可测试性。

  2. 不可变性:保证了程序是无状态的,很多难解的bug往往是由各种复杂的状态引起的。比如发现某些情况下程序运行有问题,是某一个状态引起的,但是这个状态有1000种可能性,在10000个地方都有对这个状态进行操作。数据不可变性同时保证了函数没有“副作用”。

  3. 高阶函数:函数式编程中的函数可以作为参数传递给其他函数,也可以作为返回值返回。这种函数作为一等公民(first class method)的特性,使得函数式编程具有更高的抽象能力和灵活性。

  4. 延迟计算:函数式编程中的计算是延迟计算的,即只有在需要结果时才进行计算。这种特性可以提高程序的效率和性能,也可以避免不必要的计算和资源浪费。

  5. 函数组合:函数式编程中的函数可以通过组合来创建更复杂的函数。这种特性可以提高程序的可读性和可维护性,也可以避免代码重复和冗余。

倒序递归化(tail call optimization):函数调用要压栈保存现场,递归层次过深,压栈过多会引发性能问题。所以引入倒序递归优化,每次递归时都会重用栈,提升性能。

  1. 模式匹配:函数式编程中的模式匹配可以根据输入参数的不同,选择不同的函数实现。这种特性可以提高程序的灵活性和可扩展性,也可以避免使用大量的if-else语句。

函数式编程的特性使得它在处理复杂问题时具有更高的抽象能力和灵活性,也可以提高程序的可读性、可维护性和可测试性。因此,在一些需要处理大量数据和并发访问的场景中,函数式编程已经成为了一种重要的编程范式。

函数式编程使用场景(以 Lambda 表达式为例)

在C++中,lambda表达式可以用于以下场景:

  1. STL算法中的函数对象参数:STL算法中的很多函数都需要一个函数对象作为参数,例如sort、find_if等。使用lambda表达式可以快速定义一个简单的函数对象,例如:
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; });

这里使用lambda表达式定义了一个简单的函数对象,用于对vector进行排序。

  1. STL容器中的算法:STL容器中也有很多算法,例如for_each、transform等,这些算法也可以使用lambda表达式作为参数,例如:
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
std::for_each(vec.begin(), vec.end(), [](int x) { std::cout << x << " "; });

这里使用lambda表达式定义了一个简单的函数,用于输出vector中的每个元素。

  1. C++11中的多线程编程:C++11中引入了std::thread库,可以用于多线程编程。使用lambda表达式可以快速定义一个简单的线程函数,例如:
std::thread t([]() { std::cout << "Hello, world!" << std::endl; });
t.join();

注意:这里 g++ 编译需要加 -pthread 参数
除了上述提到的场景,lambda表达式在C++中还可以用于以下场景:

  1. STL中的函数对象适配器:STL中提供了一些函数对象适配器,例如std::bind、std::mem_fn等,这些适配器可以将一个函数对象转换为另一个函数对象。使用lambda表达式可以快速定义一个简单的函数对象,然后使用适配器进行转换,例如:
std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 5; });
auto index = std::distance(vec.begin(), it);

这里使用lambda表达式定义了一个简单的函数对象,用于查找vector中第一个大于5的元素,并返回其下标。

  1. C++11中的函数式编程:C++11中引入了一些函数式编程的特性,例如std::function、std::bind、std::placeholders等,这些特性可以用于实现函数的柯里化、部分应用等高级编程技巧。使用lambda表达式可以快速定义一个简单的函数对象,然后使用这些特性进行高级编程,例如:
auto add = [](int a, int b) { return a + b; };
auto add5 = std::bind(add, std::placeholders::_1, 5);
std::cout << add5(3) << std::endl; // 输出8

这里使用lambda表达式定义了一个简单的加法函数对象,然后使用std::bind进行柯里化,得到一个新的函数对象,用于将任意一个数加5。

总之,lambda表达式在C++中可以用于很多场景,可以提高代码的简洁性和可读性。但是,在编写复杂的函数时,应该使用命名函数来提高代码的可维护性和可读性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值