匿名函数匿名函数(英語: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']
上述 该示例中的匿名函数就是lambda表达式: lambda x,y: cmp(...)
该匿名函数接受两个变量 a = ['three', 'two', 'four']
a.sort(lambda x,y: cmp(len(x), len(y)))
print a
['two', 'four', 'three']
语言列表
示例PythonPython用lambda语法定义匿名函数,只需用表达式而无需声明 # 以下两种相等同
# 1.不使用匿名函数
def f(x):
return x * x
# 2.使用匿名函数
lambda x: x * x
JavaScriptJavaScript支持匿名函数。 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();
PHPPHP 4.0.1之前不支持匿名函数[5]。 4.0.1 至 5.3PHP 4.0.1新增加了 $foo = create_function('$x', 'return $x*$x;');
$bar = create_function("\$x", "return \$x*\$x;");
echo $foo(10);
要注意的是,新函数本身及其变量都要放在单引号里面,如果要放在双引号之内,美元符号“$”则需要转码成为“\$”。 5.3PHP 5.3新增加了 $x = 3;
$func = function($z) { return $z *= 2; };
echo $func($x); // 输出结果为6
上述例子中的 虽然PHP 5.3支持闭包,但还需要像这样明确标识其变量: $x = 3;
$func = function() use(&$x) { $x *= 2; };
$func();
echo $x; // 输出结果为6
C++C++ 98/03C++ 98/03标准并不原生支持匿名函数。不过可以利用Boost库的Boost.Lambda来实现一个匿名函数[8]。 C++ 11C++11标准提供了匿名函數的支持,在《ISO/IEC 14882:2011》(C++11标准文档)中叫做lambda表達式[9]。一個lambda表達式有如下的形式: [capture] (parameters) mutable exception attribute -> 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& x) { ++x; } // 沒有return語句 -> lambda函數的返回值為void
[]() { ++global_x; } // 沒有參數,僅僅是訪問一個全局變量
[]{ ++global_x; } // 與前者相同,()可以被省略
在上面的第一個例子中這個無名函數的返回值是 返回值類型可以显式指定,如下所示: [](int x, int y) -> int { int z = x + y; return z; }
在這個例子中,一個臨時變量, lambda函數可以捕获lambda函數外的具有automatic storage duration的变量,即函数的局部变量与函数形参变量。因而,具有static storage duration的变量不能被lambda捕获,只能直接使用,这包括静态局部变量。函数体与這些變量的集合合起来称做閉包。这些外部变量在聲明lambda表達式時列在在方括號 [] // 沒有定義任何變量,但必须列出空的方括号。在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表达式可以显式或隐式捕捉 lambda函数的函数体中,可以访问下述变量:
lambda函数的数据类型是函数对象,保存时必须用 #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++14C++11中捕获机制的局限
C++14增加了广义捕获(Generalized capture),或称“初始化捕获”。[10]即在捕获子句(capture clause)中增加并初始化新的变量,该变量不需要在lambda表达式所处的闭包域(enclosing scope)中存在;即使在闭包域中存在也会被新变量覆盖(override)。新变量类型由它的初始化表达式推导。也就是说可以创建新的变量并在捕获子句中对其进行初始化。这种方式称之为带有初始化程序的捕获或者广义lambda捕获。一个用途是可以从闭包域中捕获只供移动的变量并使用它。形如[mVar1 = localVar1, mVar2 = std::move(localVar2)](){}; C++14还允许lambda函数的形参使用 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表达式可以嵌套定义。 参考资料
外部链接 |
Portal di Ensiklopedia Dunia