fbpx
维基百科

匿名函数

匿名函数(英語:Anonymous Function)在计算机编程中是指一类无需定义标识符(函数名)的函数子程序,普遍存在于多种编程语言中。

1958年LISP首先采用匿名函数,自此之后,越来越多编程语言陆续采用,主流的编程语言如PHP[1]C++[2]也陸續采用。

用途

排序

尝试将类按名称排序:

a = [10, '10', 10.0] a.sort(lambda x,y: cmp(x.__class__.__name__, y.__class__.__name__)) print a [10.0, 10, '10'] 

上述 10.0 的类名是“float”,10 的类名是“int”而 '10' 的类名是“str”,排列后的顺序为“float”“int”,接着是“str”。

该示例中的匿名函数就是lambda表达式:

lambda x,y: cmp(...) 

该匿名函数接受两个变量 xy ,通过内部函数 cmp() 返回两者的比较值,下面的例子将按长度为字符串列表排序:

a = ['three', 'two', 'four'] a.sort(lambda x,y: cmp(len(x), len(y))) print a ['two', 'four', 'three'] 

语言列表

语言 支持 备注
ActionScript  
C   在有clang和llvm的compiler-rt程序库的环境下支援
C#   從C# 3.0 (.Net Farmework 3.5)開始支援
C++   C++11开始支援,标准中称之为lambda表达式(lambda expression)[3][2]
Clojure  
Curl  
D  
Delphi   从Delphi 2009开始支援
Dylan  
Erlang  
F#  
Frink  
Go  
Haskell  
Java   Java 8开始支援[4]
JavaScript  
Kotlin  
Lisp  
Logtalk  
Lua  
Mathematica  
Matlab  
ML语言
(Objective Caml, Standard ML, etc.)
 
Octave  
Object Pascal   原生支援匿名函数,其正式名称为“匿名方法”(anonymous method)。Oxygene Object Pascal也支持匿名函数。
Objective-C (Mac OS X 10.6+)   称作“块”(block)
Pascal  
Perl  
PHP   从PHP 5.3.0开始支援真匿名函数,之前则只支持部分匿名函数
Python   Python用lambda语法定义匿名函数,只需用表达式而无需声明
R  
Ruby   Ruby的匿名函数源自Smalltalk,也同样叫“块”(block)。
Rust   Rust的匿名函式可以使用“閉包”(Closures)來實現。
Scala  
Scheme  
Smalltalk   Smalltalk的匿名函数称为“块”(block)
Tcl  
Visual Basic .NET v9  
Visual Prolog v 7.2  
Vala  

示例

Python

Python用lambda语法定义匿名函数,只需用表达式而无需声明

# 以下两种相等同 # 1.不使用匿名函数 def f(x): return x * x # 2.使用匿名函数 lambda x: x * x 

JavaScript

JavaScript支持匿名函数。

alert((function(x){ return x*x; })(10)); // 提示100 

小书签也经常使用这种结构,例如下面的一个小书签就将当前网页的标题显示为其URL:

javascript:document.title=location.href; 

然而,由于该赋值语句返回了一个值(即URL本身),很多浏览器会同时创建一个新的页面显示这个值。

取而代之,下面的匿名函数就可以做到不返回任何值:

javascript:(function(){document.title=location.href;})(); 

第一对圆括号中的函数(“(function(){document.title=location.href;})”)用作声明一个匿名函数,而最后的一对圆括号则用来执行这个函数。同等用法有:

javascript:var f = function(){document.title=location.href;}; f(); 

PHP

PHP 4.0.1之前不支持匿名函数[5]

4.0.1 至 5.3

PHP 4.0.1新增加了create_function函数,这是匿名函数的雏形。该函数能创建一个随机命名的新函数并以字符串形式返回新函数的函数名。

$foo = create_function('$x', 'return $x*$x;'); $bar = create_function("\$x", "return \$x*\$x;"); echo $foo(10); 

要注意的是,新函数本身及其变量都要放在单引号里面,如果要放在双引号之内,美元符号“$”则需要转码成为“\$”。

5.3

PHP 5.3新增加了Closure类,以及能使类的实例可被调用的“魔术方法”__invoke()[6]。Lambda函数都是编译器的一种“花招”[7],它能产生新的能被调用的Closure实例,就像函数能被调用一样。

$x = 3; $func = function($z) { return $z *= 2; }; echo $func($x); // 输出结果为6 

上述例子中的$funcClosure类的一个实例,而echo $func()则相当于是$func->__invoke($z)。PHP 5.3模仿使用匿名函数,但并非支持真匿名函数,因为PHP的函数仍非第一类函数。

虽然PHP 5.3支持闭包,但还需要像这样明确标识其变量:

$x = 3; $func = function() use(&$x) { $x *= 2; }; $func(); echo $x; // 输出结果为6 

$func引用了变量$x(&$x),在调用的时候就会修改原来的$x,其结果在函数以外的地方也是可见的。

C++

C++ 98/03

C++ 98/03标准并不原生支持匿名函数。不过可以利用Boost库的Boost.Lambda来实现一个匿名函数[8]

C++ 11

C++11标准提供了匿名函數的支持,在《ISO/IEC 14882:2011》(C++11标准文档)中叫做lambda表達式[9]。一個lambda表達式有如下的形式:

[capture] (parameters) mutable exception attribute -> return_type { body } 

必须用方括号括起来的capture列表来开始一个lambda表达式的定义。

lambda函数的形参表比普通函数的形参表多了3条限制:

  1. 参数不能有缺省值
  2. 不能有可变长参数列表
  3. 不能有无名参数

如果lambda函数沒有形參且没有mutable、exception或attribute声明,那麼参数的空圆括號可以省略。但如果需要给出mutable、exception或attribute声明,那么参数即使为空,圆括号也不能省略。

如果函數體只有一個return語句,或者返回值類型為void,那麼返回值類型声明可以被省略:

[capture](parameters){body} 

一個lambda函數的例子如下:

[](int x, int y) { return x + y; } // 從return語句中隱式獲得的返回值類型 [](int& x) { ++x; } // 沒有return語句 -> lambda函數的返回值為void []() { ++global_x; } // 沒有參數,僅僅是訪問一個全局變量 []{ ++global_x; } // 與前者相同,()可以被省略 

在上面的第一個例子中這個無名函數的返回值是decltype(x+y)。如果lambda函數體的形式是return expression,或者甚麼也没返回,或者所有返回語句用decltype都能檢測到同一類型,那麼返回值類型可以被省略。

返回值類型可以显式指定,如下所示:

[](int x, int y) -> int { int z = x + y; return z; } 

在這個例子中,一個臨時變量,z,被創建來儲存中間過程。與一般的函數一樣,中間值在調用的前後並不存在。甚麼也沒有返回的lambda表達式無需顯式指定返回值,沒有必要寫-> void代碼。

lambda函數可以捕获lambda函數外的具有automatic storage duration的变量,即函数的局部变量与函数形参变量。因而,具有static storage duration的变量不能被lambda捕获,只能直接使用,这包括静态局部变量。函数体与這些變量的集合合起来称做閉包。这些外部变量在聲明lambda表達式時列在在方括號[]中。空的方括号表示没有外界变量被capture或者按照默认方式捕获外界变量。這些變量被傳值捕獲或者引用捕獲。对于传值捕获的变量,默认为只读(这是由于lambda表达式生成的为一个函数对象,它的operator()成员缺省有const属性)。修改这些傳值捕獲变量将导致编译报错。但在lambda表达式的参数表的圆括号后面使用mutable关键字,就允许lambda函数体内的语句修改傳值捕獲变量,这些修改与lambda表达式(实际上是用函数对象实现)有相同的生命期,但不影响被传值捕获的外部变量的值。lambda函数可以直接使用具有static存储期的变量。如果在lambda函数的捕获列表中给出了static存储期的变量,编译时会给出警告,仍然按照lambda函数直接使用这些外部变量来处理。因此具有static存储期的变量即使被声明为传值捕获,修改该变量实际上直接修改了这些外部变量。编译器生成lambda函數对应的函数对象时,不会用函数对象的数据成员来保持被“捕获”的static存储期的变量。示例:

[] // 沒有定義任何變量,但必须列出空的方括号。在Lambda表達式中嘗試使用任何外部變量都會導致編譯錯誤。 [x, &y] // x是按值傳遞,y是按引用傳遞 [&] // 任何被使用到的外部變量都按引用傳入。 [=] // 任何被使用到的外部變量都按值傳入。 [&, x] // x按值傳入。其它變量按引用傳入。 [=, &z] // z按引用傳入。其它變量按值傳入。 

下面這個例子展示了lambda表達式的使用:

std::vector<int> some_list{ 1, 2, 3, 4, 5 }; int total = 0; std::for_each(begin(some_list), end(some_list),   [&total](int x) { total += x; }  ); 

在类的非静态成员函数中定义的lambda表达式可以显式或隐式捕捉this指针,从而可以引用所在类对象的数据成员与函数成员。对象的this指针必需显式捕获声明。因此,被捕获的类的数据成员总是用this指针来访问,如果this所指的对象不存在,则this是空悬指针。解决办法是在定义lambda之前用局部变量复制一份数据成员的值,然后捕获这个局部变量的值。

lambda函数的函数体中,可以访问下述变量:

  • 函数参数
  • 局部声明的变量
  • 类数据成员:要求lambda表达式声明在类成员函数中,对象的this指针必需显式捕获声明。
  • 具有静态存储期的变量(如全局变量)。一般情况下,lambda是用来捕获局部变量的,如果用其来捕获全局变量或者静态变量,那么编译器会报warning
  • 被捕获的外部变量
    • 显式捕获的变量
    • 隐式捕获的变量,使用默认捕获模式(传值或引用)来访问。

lambda函数的数据类型是函数对象,保存时必须用std::function模板类型或auto关键字。 例如:

#include <functional> #include <vector> #include <iostream> double eval(std::function <double(double)> f, double x = 2.0) {  return f(x); } int main() {  std::function<double(double)> f0 = [](double x){return 1;};  auto f1 = [](double x){return x;};  decltype(f0) fa[3] = {f0,f1,[](double x){return x*x;}};  std::vector<decltype(f0)> fv = {f0,f1};  fv.push_back ([](double x){return x*x;});  for(int i=0;i<fv.size();i++)  std::cout << fv[i](2.0) << std::endl;  for(int i=0;i<3;i++)  std::cout << fa[i](2.0) << std::endl;  for(auto &f : fv)  std::cout << f(2.0) << std::endl;  for(auto &f : fa)  std::cout << f(2.0) << std::endl;  std::cout << eval(f0) << std::endl;  std::cout << eval(f1) << std::endl;  std::cout << eval([](double x){return x*x;}) << std::endl;  return 0; } 

一个lambda函数的捕捉表达式为空,则可以用普通函数指针存储或调用。例如:

auto a_lambda_func = [](int x) { /*...*/ }; void (* func_ptr)(int) = a_lambda_func; func_ptr(4); //calls the lambda. 

C++14

C++11中捕获机制的局限

  1. lambda捕获的是局部变量或形参,不管是按值还是按引用捕获,这些都是具名的左值对象。而右值对象是匿名对象,无法被捕获。
  2. 按值捕获时,左值是被复制到闭包中的。如果被捕获的对象是个只移动类型的对象时,因其无法被复制,就会出错。
  3. 如果被捕获的对象如果是一个占用内存较大的对象时,按值捕获显然效率很低。

C++14增加了广义捕获(Generalized capture),或称“初始化捕获”。[10]即在捕获子句(capture clause)中增加并初始化新的变量,该变量不需要在lambda表达式所处的闭包域(enclosing scope)中存在;即使在闭包域中存在也会被新变量覆盖(override)。新变量类型由它的初始化表达式推导。也就是说可以创建新的变量并在捕获子句中对其进行初始化。这种方式称之为带有初始化程序的捕获或者广义lambda捕获。一个用途是可以从闭包域中捕获只供移动的变量并使用它。形如[mVar1 = localVar1, mVar2 = std::move(localVar2)](){};

C++14还允许lambda函数的形参使用auto关键字作为其类型,这实质上是函数对象的operator()成员作为模板函数;并且允许可变参数模板

auto a_lambda_func = [data1=101](int x) { /*...*/ }; //广义捕获,实质上是在函数对象中增加了数据成员data1并初始化 auto ptr = std::make_unique<int>(10); //See below for std::make_unique auto lambda1 = [ptr = std::move(ptr)] {return *ptr;}  //大致等效于:  auto lambda2 = [ptr = std::make_unique<int>(10)] {return *ptr;} auto lambda3 = [](auto x, auto y) {return x + y;} //lambda函数的形参类型为auto struct unnamed_lambda //这相当于函数对象: {  template<typename T, typename U>  auto operator()(T x, U y) const {return x + y;} }; auto lambda4 = [](auto&&... params) //可变参数的函数模板  {  return (foo(std::forward<decltype(params)>(params)...));  } 

Visual Basic.NET

匿名函数或lambda表达式即无名的函数或过程,作为表达式的值。可以写为一行或多行。例如:

 Dim func1=Function(i As integer) i+10  Dim action = sub()  End Sub  Dim func2 = Function()  End Function 

可以在声明匿名函数的同时调用它。单行的lambda表达式不能使用Return关键字,其返回类型是自动推导得出;其参数要么都是用As关键字指明类型,要么全部是自动推导出类型。

lambda表达式在定义时可以使用所在上下文(context,即C++语言的闭包closure)的局部变量、参数、属性、Me等等的值,即使lambda表达式离开了定义时所在的context,这些被使用的局部变量等的值仍然有效。这是因为lambda表达式在定义时把所用到的context的值保存到它自己的定义类中。lambda表达式可以嵌套定义。

参考资料

  1. ^ Anonymous functions. [2014-04-27]. (原始内容于2014-03-27) (英语). Anonymous functions, also known as closures, allow the creation of functions which have no specified name. They are most useful as the value of callback parameters, but they have many other uses. 
  2. ^ 2.0 2.1 5.1.2 Lambda expressions. ISO/IEC 14882:2011. [2014-04-27]. (原始内容于2014-04-27) (英语). Lambda expressions provide a concise way to create simple function objects. 
  3. ^ Lambda expressions and closures for C++ (PDF). V Samko; J Willcock, J Järvi, D Gregor, A Lumsdaine. 2006-02-26 [2010-06-01]. (原始内容 (PDF)于2011-07-28). 
  4. ^ Java 7 Features. Sun Microsystems. 2010-02-09 [2010-11-21]. (原始内容存档于2012-02-07). 
  5. ^ http://php.net/create_function (页面存档备份,存于互联网档案馆) the top of the page indicates this with "(PHP 4 >= 4.0.1, PHP 5)"
  6. ^ 存档副本. [2011-08-13]. (原始内容于2011-07-24). 
  7. ^ 存档副本. [2011-08-13]. (原始内容于2011-07-24). 
  8. ^ Chapter 16. Boost.Lambda - 1.55.0. [2014-04-27]. (原始内容于2014-04-27) (英语). 
  9. ^ 该标准文档可以在ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++ (页面存档备份,存于互联网档案馆)购买,或者可参看2012年一月份的标准草案文件N3337 (页面存档备份,存于互联网档案馆),第5.1.2节的Lambda expressions
  10. ^ MSDN: In C++14, you can introduce and initialize new variables in the capture clause, without the need to have those variables exist in the lambda function’s enclosing scope. The initialization can be expressed as any arbitrary expression; the type of the new variable is deduced from the type produced by the expression. One benefit of this feature is that in C++14 you can capture move-only variables (such as std::unique_ptr) from the surrounding scope and use them in a lambda.

外部链接

  • 《深入理解PHP内核》第四章 函数的实现 第四节 匿名函数及闭包(页面存档备份,存于互联网档案馆

匿名函数, 英語, anonymous, function, 在计算机编程中是指一类无需定义标识符, 函数名, 的函数或子程序, 普遍存在于多种编程语言中, 1958年lisp首先采用, 自此之后, 越来越多编程语言陆续采用, 主流的编程语言如php, 和c, 也陸續采用, 目录, 用途, 排序, 语言列表, 示例, python, javascript, visual, basic, 参考资料, 外部链接用途, 编辑排序, 编辑, 尝试将类按名称排序, sort, lambda, class, name, cla. 匿名函数 英語 Anonymous Function 在计算机编程中是指一类无需定义标识符 函数名 的函数或子程序 普遍存在于多种编程语言中 1958年LISP首先采用匿名函数 自此之后 越来越多编程语言陆续采用 主流的编程语言如PHP 1 和C 2 也陸續采用 目录 1 用途 1 1 排序 2 语言列表 3 示例 3 1 Python 3 2 JavaScript 3 3 PHP 3 3 1 4 0 1 至 5 3 3 3 2 5 3 3 4 C 3 4 1 C 98 03 3 4 2 C 11 3 4 3 C 14 3 5 Visual Basic NET 4 参考资料 5 外部链接用途 编辑排序 编辑 尝试将类按名称排序 a 10 10 10 0 a sort lambda x y cmp x class name y class name print a 10 0 10 10 上述 10 0 的类名是 float 10 的类名是 int 而 10 的类名是 str 排列后的顺序为 float int 接着是 str 该示例中的匿名函数就是lambda表达式 lambda x y cmp 该匿名函数接受两个变量 x 和 y 通过内部函数 cmp 返回两者的比较值 下面的例子将按长度为字符串列表排序 a three two four a sort lambda x y cmp len x len y print a two four three 语言列表 编辑语言 支持 备注ActionScript C 在有clang和llvm的compiler rt程序库的环境下支援C 從C 3 0 Net Farmework 3 5 開始支援C 从C 11开始支援 标准中称之为lambda表达式 lambda expression 3 2 Clojure Curl D Delphi 从Delphi 2009开始支援Dylan Erlang F Frink Go Haskell Java 从Java 8开始支援 4 JavaScript Kotlin Lisp Logtalk Lua Mathematica Matlab ML语言 Objective Caml Standard ML etc Octave Object Pascal 原生支援匿名函数 其正式名称为 匿名方法 anonymous method Oxygene Object Pascal也支持匿名函数 Objective C Mac OS X 10 6 称作 块 block Pascal Perl PHP 从PHP 5 3 0开始支援真匿名函数 之前则只支持部分匿名函数Python Python用lambda语法定义匿名函数 只需用表达式而无需声明R Ruby Ruby的匿名函数源自Smalltalk 也同样叫 块 block Rust Rust的匿名函式可以使用 閉包 Closures 來實現 Scala Scheme Smalltalk Smalltalk的匿名函数称为 块 block Tcl Visual Basic NET v9 Visual Prolog v 7 2 Vala 示例 编辑Python 编辑 Python用lambda语法定义匿名函数 只需用表达式而无需声明 以下两种相等同 1 不使用匿名函数 def f x return x x 2 使用匿名函数 lambda x x x JavaScript 编辑 JavaScript支持匿名函数 alert function x return x x 10 提示100 小书签也经常使用这种结构 例如下面的一个小书签就将当前网页的标题显示为其URL javascript document title location href 然而 由于该赋值语句返回了一个值 即URL本身 很多浏览器会同时创建一个新的页面显示这个值 取而代之 下面的匿名函数就可以做到不返回任何值 javascript function document title location href 第一对圆括号中的函数 function document title location href 用作声明一个匿名函数 而最后的一对圆括号则用来执行这个函数 同等用法有 javascript var f function document title location href f PHP 编辑 PHP 4 0 1之前不支持匿名函数 5 4 0 1 至 5 3 编辑 PHP 4 0 1新增加了create function函数 这是匿名函数的雏形 该函数能创建一个随机命名的新函数并以字符串形式返回新函数的函数名 foo create function x return x x bar create function x return x x echo foo 10 要注意的是 新函数本身及其变量都要放在单引号里面 如果要放在双引号之内 美元符号 则需要转码成为 5 3 编辑 PHP 5 3新增加了Closure类 以及能使类的实例可被调用的 魔术方法 invoke 6 Lambda函数都是编译器的一种 花招 7 它能产生新的能被调用的Closure实例 就像函数能被调用一样 x 3 func function z return z 2 echo func x 输出结果为6 上述例子中的 func是Closure类的一个实例 而echo func 则相当于是 func gt invoke z PHP 5 3模仿使用匿名函数 但并非支持真匿名函数 因为PHP的函数仍非第一类函数 虽然PHP 5 3支持闭包 但还需要像这样明确标识其变量 x 3 func function use amp x x 2 func echo x 输出结果为6 func引用了变量 x amp x 在调用的时候就会修改原来的 x 其结果在函数以外的地方也是可见的 C 编辑 C 98 03 编辑 C 98 03标准并不原生支持匿名函数 不过可以利用Boost库的Boost Lambda来实现一个匿名函数 8 C 11 编辑 C 11标准提供了匿名函數的支持 在 ISO IEC 14882 2011 C 11标准文档 中叫做lambda表達式 9 一個lambda表達式有如下的形式 capture parameters mutable exception attribute gt return type body 必须用方括号括起来的capture列表来开始一个lambda表达式的定义 lambda函数的形参表比普通函数的形参表多了3条限制 参数不能有缺省值 不能有可变长参数列表 不能有无名参数如果lambda函数沒有形參且没有mutable exception或attribute声明 那麼参数的空圆括號可以省略 但如果需要给出mutable exception或attribute声明 那么参数即使为空 圆括号也不能省略 如果函數體只有一個return語句 或者返回值類型為void 那麼返回值類型声明可以被省略 capture parameters body 一個lambda函數的例子如下 int x int y return x y 從return語句中隱式獲得的返回值類型 int amp x x 沒有return語句 gt lambda函數的返回值為void global x 沒有參數 僅僅是訪問一個全局變量 global x 與前者相同 可以被省略 在上面的第一個例子中這個無名函數的返回值是decltype x y 如果lambda函數體的形式是return i expression i 或者甚麼也没返回 或者所有返回語句用decltype都能檢測到同一類型 那麼返回值類型可以被省略 返回值類型可以显式指定 如下所示 int x int y gt int int z x y return z 在這個例子中 一個臨時變量 z 被創建來儲存中間過程 與一般的函數一樣 中間值在調用的前後並不存在 甚麼也沒有返回的lambda表達式無需顯式指定返回值 沒有必要寫 gt void代碼 lambda函數可以捕获lambda函數外的具有automatic storage duration的变量 即函数的局部变量与函数形参变量 因而 具有static storage duration的变量不能被lambda捕获 只能直接使用 这包括静态局部变量 函数体与這些變量的集合合起来称做閉包 这些外部变量在聲明lambda表達式時列在在方括號 和 中 空的方括号表示没有外界变量被capture或者按照默认方式捕获外界变量 這些變量被傳值捕獲或者引用捕獲 对于传值捕获的变量 默认为只读 这是由于lambda表达式生成的为一个函数对象 它的operator 成员缺省有const属性 修改这些傳值捕獲变量将导致编译报错 但在lambda表达式的参数表的圆括号后面使用mutable关键字 就允许lambda函数体内的语句修改傳值捕獲变量 这些修改与lambda表达式 实际上是用函数对象实现 有相同的生命期 但不影响被传值捕获的外部变量的值 lambda函数可以直接使用具有static存储期的变量 如果在lambda函数的捕获列表中给出了static存储期的变量 编译时会给出警告 仍然按照lambda函数直接使用这些外部变量来处理 因此具有static存储期的变量即使被声明为传值捕获 修改该变量实际上直接修改了这些外部变量 编译器生成lambda函數对应的函数对象时 不会用函数对象的数据成员来保持被 捕获 的static存储期的变量 示例 沒有定義任何變量 但必须列出空的方括号 在Lambda表達式中嘗試使用任何外部變量都會導致編譯錯誤 x amp y x是按值傳遞 y是按引用傳遞 amp 任何被使用到的外部變量都按引用傳入 任何被使用到的外部變量都按值傳入 amp x x按值傳入 其它變量按引用傳入 amp z z按引用傳入 其它變量按值傳入 下面這個例子展示了lambda表達式的使用 std vector lt int gt some list 1 2 3 4 5 int total 0 std for each begin some list end some list amp total int x total x 在类的非静态成员函数中定义的lambda表达式可以显式或隐式捕捉this指针 从而可以引用所在类对象的数据成员与函数成员 对象的this指针必需显式捕获声明 因此 被捕获的类的数据成员总是用this指针来访问 如果this所指的对象不存在 则this是空悬指针 解决办法是在定义lambda之前用局部变量复制一份数据成员的值 然后捕获这个局部变量的值 lambda函数的函数体中 可以访问下述变量 函数参数 局部声明的变量 类数据成员 要求lambda表达式声明在类成员函数中 对象的this指针必需显式捕获声明 具有静态存储期的变量 如全局变量 一般情况下 lambda是用来捕获局部变量的 如果用其来捕获全局变量或者静态变量 那么编译器会报warning 被捕获的外部变量 显式捕获的变量 隐式捕获的变量 使用默认捕获模式 传值或引用 来访问 lambda函数的数据类型是函数对象 保存时必须用std function模板类型或auto关键字 例如 include lt functional gt include lt vector gt include lt iostream gt double eval std function lt double double gt f double x 2 0 return f x int main std function lt double double gt f0 double x return 1 auto f1 double x return x decltype f0 fa 3 f0 f1 double x return x x std vector lt decltype f0 gt fv f0 f1 fv push back double x return x x for int i 0 i lt fv size i std cout lt lt fv i 2 0 lt lt std endl for int i 0 i lt 3 i std cout lt lt fa i 2 0 lt lt std endl for auto amp f fv std cout lt lt f 2 0 lt lt std endl for auto amp f fa std cout lt lt f 2 0 lt lt std endl std cout lt lt eval f0 lt lt std endl std cout lt lt eval f1 lt lt std endl std cout lt lt eval double x return x x lt lt std endl return 0 一个lambda函数的捕捉表达式为空 则可以用普通函数指针存储或调用 例如 auto a lambda func int x void func ptr int a lambda func func ptr 4 calls the lambda C 14 编辑 C 11中捕获机制的局限 lambda捕获的是局部变量或形参 不管是按值还是按引用捕获 这些都是具名的左值对象 而右值对象是匿名对象 无法被捕获 按值捕获时 左值是被复制到闭包中的 如果被捕获的对象是个只移动类型的对象时 因其无法被复制 就会出错 如果被捕获的对象如果是一个占用内存较大的对象时 按值捕获显然效率很低 C 14增加了广义捕获 Generalized capture 或称 初始化捕获 10 即在捕获子句 capture clause 中增加并初始化新的变量 该变量不需要在lambda表达式所处的闭包域 enclosing scope 中存在 即使在闭包域中存在也会被新变量覆盖 override 新变量类型由它的初始化表达式推导 也就是说可以创建新的变量并在捕获子句中对其进行初始化 这种方式称之为带有初始化程序的捕获或者广义lambda捕获 一个用途是可以从闭包域中捕获只供移动的变量并使用它 形如 mVar1 localVar1 mVar2 std move localVar2 C 14还允许lambda函数的形参使用auto关键字作为其类型 这实质上是函数对象的operator 成员作为模板函数 并且允许可变参数模板 auto a lambda func data1 101 int x 广义捕获 实质上是在函数对象中增加了数据成员data1并初始化 auto ptr std make unique lt int gt 10 See below for std make unique auto lambda1 ptr std move ptr return ptr 大致等效于 auto lambda2 ptr std make unique lt int gt 10 return ptr auto lambda3 auto x auto y return x y lambda函数的形参类型为auto struct unnamed lambda 这相当于函数对象 template lt typename T typename U gt auto operator T x U y const return x y auto lambda4 auto amp amp params 可变参数的函数模板 return foo std forward lt decltype params gt params Visual Basic NET 编辑 匿名函数或lambda表达式即无名的函数或过程 作为表达式的值 可以写为一行或多行 例如 Dim func1 Function i As integer i 10 Dim action sub End Sub Dim func2 Function End Function 可以在声明匿名函数的同时调用它 单行的lambda表达式不能使用Return关键字 其返回类型是自动推导得出 其参数要么都是用As关键字指明类型 要么全部是自动推导出类型 lambda表达式在定义时可以使用所在上下文 context 即C 语言的闭包closure 的局部变量 参数 属性 Me等等的值 即使lambda表达式离开了定义时所在的context 这些被使用的局部变量等的值仍然有效 这是因为lambda表达式在定义时把所用到的context的值保存到它自己的定义类中 lambda表达式可以嵌套定义 参考资料 编辑 Anonymous functions 2014 04 27 原始内容存档于2014 03 27 英语 Anonymous functions also known as closures allow the creation of functions which have no specified name They are most useful as the value of callback parameters but they have many other uses 2 0 2 1 5 1 2 Lambda expressions ISO IEC 14882 2011 2014 04 27 原始内容存档于2014 04 27 英语 Lambda expressions provide a concise way to create simple function objects Lambda expressions and closures for C PDF V Samko J Willcock J Jarvi D Gregor A Lumsdaine 2006 02 26 2010 06 01 原始内容存档 PDF 于2011 07 28 Java 7 Features Sun Microsystems 2010 02 09 2010 11 21 原始内容存档于2012 02 07 http php net create function 页面存档备份 存于互联网档案馆 the top of the page indicates this with PHP 4 gt 4 0 1 PHP 5 存档副本 2011 08 13 原始内容存档于2011 07 24 存档副本 2011 08 13 原始内容存档于2011 07 24 Chapter 16 Boost Lambda 1 55 0 2014 04 27 原始内容存档于2014 04 27 英语 该标准文档可以在ISO IEC 14882 2011 Information technology Programming languages C 页面存档备份 存于互联网档案馆 购买 或者可参看2012年一月份的标准草案文件N3337 页面存档备份 存于互联网档案馆 第5 1 2节的Lambda expressions MSDN In C 14 you can introduce and initialize new variables in the capture clause without the need to have those variables exist in the lambda function s enclosing scope The initialization can be expressed as any arbitrary expression the type of the new variable is deduced from the type produced by the expression One benefit of this feature is that in C 14 you can capture move only variables such as std unique ptr from the surrounding scope and use them in a lambda 外部链接 编辑 深入理解PHP内核 第四章 函数的实现 第四节 匿名函数及闭包 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title 匿名函数 amp oldid 76036454, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。