Lambda表达式是一种用于创建匿名函数的语法构造。它可以在需要函数对象的地方使用,而无需显式定义一个命名函数。
Lambda表达式有如下优点:
python中的Lambda
在Python中,Lambda表达式用于创建匿名函数。Lambda表达式的语法如下:
lambda arguments: expression
1. 将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。
greeting = lambda : "Hello, world!" print (greeting()) add = lambda x, y: x + y print (add(3 , 4 ))
2. 将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。
time.sleep=lambda x:None time.sleep(3 )
在后续代码中调用time库的sleep函数将不会执行原有的功能
3. 将lambda函数作为参数传递给其他函数。
numbers = [1 , 2 , 3 , 4 , 5 ] squared = map (lambda x: x**2 , numbers) print (list (squared))
部分Python内置函数接受函数作为参数 ,典型的此类内置函数有 这些:
filter函数
filter (lambda x: x % 3 == 0 , [1 , 2 , 3 ])
sorted函数
sorted ([1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ], key=lambda x: abs (5 -x))
map函数
map (lambda x: x+1 , [1 , 2 ,3 ])
reduce函数
reduce(lambda a, b: '{}, {}' .format (a, b), [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ])
排序:
students = [ {"name" : "Alice" , "score" : 80 }, {"name" : "Bob" , "score" : 90 }, {"name" : "Charlie" , "score" : 70 } ] students.sort(key=lambda student: student["score" ]) print (students)
在上述示例中,Lambda表达式用于创建匿名函数,并在不同的上下文中使用。Lambda表达式可以在需要函数对象的地方直接使用,无需显式定义一个命名函数。
C++中的Lambda
Lambda 表达式的各个部分
下面是作为第三个参数 std::sort()
传递给函数的简单 lambda:
#include <algorithm> #include <cmath> void abssort (float * x, unsigned n) { std::sort (x, x + n, [](float a, float b) { return (std::abs (a) < std::abs (b)); } ); }
下图显示了 lambda 语法的各个部分:
capture 子句(在 C++ 规范中也称为 Lambda 引导。)
参数列表(可选)。 (也称为 Lambda 声明符)
mutable 规范(可选)。
exception-specification(可选)。
trailing-return-type(可选)。
Lambda 体。
捕获列表 [ ]
捕获列表是零或多个捕获符的逗号分隔符列表,可选地以默认捕获符开始(仅有的默认捕获符是 & 和 = )。默认情况下,从lambda生成的类都包含一个对应该lambda所捕获变量的数据成员。类似任何普通类地数据成员,lambda的数据成员也在lambda对象创建时被初始化。类似参数传递,变量的捕获方式也可以是值或引用。
值捕获:
void func () { int i = 100 ; auto f = [i] { return i; }; i = 0 ; int j = f (); }
引用捕获:
void func () { int i = 100 ; auto f = [&i] { return i; }; i = 0 ; int j = f (); }
除了自己列出捕获列表的变量,还可以让编译器根据lambda中代码来推断我们要使用哪些变量(隐式捕获 ),用过使用&或=指示编译器推断捕获列表。&则采用引用捕获的方式,=则采用值捕获的方式。混合使用隐式捕获和显示捕获,则两者须使用不同的方式,一个为引用捕获,一个为值捕获。
lambda捕获列表:
[ ]。空捕获列表,lambda不能使用所在函数中的变量。
[=]。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
[&]。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
[this]。函数体内可以使用Lambda所在类中的成员变量。
[a]。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
[&a]。将a按引用进行传递。
[=,&a, &b]。除a和b按引用进行传递外,其他参数都按值进行传递。
[&, a, b]。除a和b按值进行传递外,其他参数都按引用进行传递。
悬垂引用:
若以引用隐式或显式捕获非引用实体,而在该实体的生存期结束之后调用lambda对象的函数调用运算符,则发生未定义行为。C++ 的闭包并不延长被捕获的引用的生存期。这同样适用于被捕获的this指针所指向的对象的生存期。
形参列表 ( )
lambda形参列表和一般的函数形参列表类似,但不允许默认实参(C14 前)。当以 auto 为形参类型时,该 lambda 为泛型 lambda(C 14 起)。与一个普通函数调用类似,调用一个lambda时给定的实参被用来初始化lambda的形参。
void func () { int i = 10 , j = 10 ; auto f = [i, &j]() mutable { i = 100 , j = 100 ; }; i = 0 , j = 0 ; f (); std::cout << i << " " << j << std::endl; }
说明符
允许以下说明符:
mutable:允许 函数体修改各个复制捕获的对象,以及调用其非 const 成员函数;
constexpr:显式指定函数调用运算符为 constexpr 函数。此说明符不存在时,若函数调用运算符恰好满足针对 constexpr 函数的所有要求,则它也会是 constexpr; (C++17 起)
consteval:指定函数调用运算符为立即函数。不能同时使用 consteval 和 constexpr。(C++20 起)
默认情况下,对于一个值被拷贝的变量,lambda不会改变其值。假如我们希望能改变一个被捕获的变量的值,就必须在参数列表后面加上关键字mutable。而一个引用捕获的变量则不受此限制。
void func () { int i = 10 , j = 10 ; auto f = [i, &j]() mutable { i = 100 , j = 100 ; }; i = 0 , j = 0 ; f (); std::cout << i << " " << j << std::endl; }
返回类型 ->
当我们需要为一个lambda定义返回类型时,需要使用尾置返回类型。返回类型若缺省,则根据函数体中的 return 语句进行推断(如果有多条return语句,需要保证类型一直,否则编译器无法自动推断)。默认情况下,如果一个lambda函数体不包含return语句,则编译器假定返回void。
void func () { auto f = []() ->double { if (1 > 2 ) return 1 ; else return 2.0 ; }; std::cout << f () << std::endl; }
如果不显示指定返回类型,则int和double两种返回类型会导致推断冲突。
函数体 { }
略,同普通函数的函数体。
综合示例
#include <iostream> #include <set> #include <vector> #include <algorithm> #include <functional> using namespace std;class UnNamedLocalFunction {private : int localVar; public : UnNamedLocalFunction (int var) : localVar (var) {} bool operator () (int val) { return val == localVar; } }; class Person {public : string firstname; string lastname; }; class LambdaFunctor {public : LambdaFunctor (int a, int b) : m_a (a), m_b (b) {} bool operator () (int n) const { return m_a < n && n < m_b; } private : int m_a; int m_b; }; class X {private : int __x, __y; public : X (int x, int y) : __x(x), __y(y) {} int operator () (int a) { return a; } int f () { return [&]() -> int { return operator ()(this ->__x + __y); }(); } int ff () { return [this ]() { return this ->__x; }(); } }; int main () { [] { cout << "hello" << endl; }(); auto I = [] { cout << "hello" << endl; }; I (); int id = 0 ; auto f = [id]()mutable { cout << "id=" << id << endl; ++id; }; id = 42 ; f (); f (); f (); cout << id << endl; int id1 = 0 ; auto f1 = [&id1]() { cout << "id1=" << id1 << endl; ++id1; }; id1 = 42 ; f1 (); f1 (); f1 (); cout << id1 << endl; int id2 = 0 ; auto f2 = [&id2](int ¶m) { cout << "id2=" << id2 << endl; ++id2; ++param; cout << "param=" << param << endl; static int x = 5 ; return id2; }; int param = 1 ; f2 (param); cout << "param=" << param << endl; auto f3 = [&]() { cout << "id=" << id << endl; cout << "id1=" << id1 << endl; cout << "id2=" << id2 << endl; cout << "param=" << param << endl; }; f3 (); cout << "id=" << id << endl; auto f4 = [=, &id]() { cout << "id=" << id << endl; id++; cout << "id1=" << id1 << endl; cout << "id2=" << id2 << endl; cout << "param=" << param << endl; }; f4 (); cout << "id=" << id << endl; auto f5 = [&, id]() { cout << "id=" << id << endl; cout << "id1=" << id1 << endl; cout << "id2=" << id2 << endl; cout << "param=" << param << endl; }; f5 (); X x_ (1 , 2 ) ; cout << "x_.f()=" << x_.f () << endl; cout << "x_.ff()=" << x_.ff () << endl; int tobefound = 5 ; auto lambda1 = [tobefound](int val) { return val == tobefound; }; bool b1 = lambda1 (5 ); UnNamedLocalFunction lambda2 (tobefound) ; bool b2 = lambda2 (5 ); cout << b1 << " " << b2 << endl; auto ll1 = [](int x) -> int { return x + 10 ; }; function<int (int x)> ll = [](int x) -> float { return x + 10.0 ; }; cout<<ll (1 )<<endl; function<bool (const Person&p1,const Person&p2)> cmp = [](const Person &p1, const Person &p2) { return p1.lastname < p2.lastname; }; set<Person, decltype (cmp) > col (cmp) ; vector<int > vec{5 , 28 , 50 , 83 , 70 , 590 , 245 , 59 , 24 }; int x = 30 , y = 100 ; vec.erase (remove_if (vec.begin (), vec.end (), [x, y](int n) { return x < n && n < y; }), vec.end ()); for_each(vec.begin (), vec.end (), [](int i) { cout << i << " " ; }); cout << endl; return 0 ; }
Reference
[1] C++ Lambda表达式的基本使用: https://blog.csdn.net/gongjianbo1992/article/details/105128849
[2] python中的lambda函数用法: https://zhuanlan.zhihu.com/p/58579207
[3] C++ 那些事: https://github.com/Light-City/CPlusPlusThings