C++ 中的Lambda表达式写法

小喵的唠叨话:

寒假之后,小喵在家里无所事事,最近用C++写代码的时候,用到了std::sort这个函数,每次用这个函数,小喵似乎都得查一下lambda表达式的写法。正好最近很闲,不如总结一下。

在Bing上搜索 C++ lambda ,第一条记录就是MSDN上的C++ lambda的介绍。本文也是基于这篇文章来写的。

那么接下来,我们分几个部分来介绍。

一、什么是Lambda表达式

MSDN上对lambda表达式的解释:

在 C++ 11 中,lambda 表达式(通常称为 “lambda”)是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法。 Lambda 通常用于封装传递给算法或异步方法的少量代码行。 [1]

看了这个解释,相信大家已经理解lambda表达式是什么。简而言之,lambda表达式就是一种定义函数的简单的方法。

举一个简单的例子:求一个数的阶乘。

这是一般的函数的写法:

// 这里要求n>=0,同时n的取值不能太大,会溢出
// 为了方便,这里并没有处理上面说到的问题
int factorial(int n) {
 int fact = 1;
 for (int i = 1; i <= n; ++ i) fact *= i;
 return fact;
}

Lambda表达式的写法:

autofactorial = [](int n) {
 int fact = 1;
 for (int i = 1; i <= n; ++ i) fact *= i;
 return fact;
};

乍一看,这两种定义方式十分的相似。但其实这是两种完全不同的方式,前一种是函数定义式,而后一种是一个表达式。factorial是变量名,等于号后面的是值,也就是一个lambda表达式,本质上是一个匿名的函数。最终factorial就是一个函数。

很多时候,我们只是直接书写lambda表达式,而不需要给他一个名字。比如排序的时候,sort可以接受一个自定义的比较函数,这时候直接书写lambda表达式即可。

二、Lambda表达式的作用

由于lambda本身其实也就是一种函数的定义方式。因此它的主要作用还是和一般函数一样。但是lambda表达式相对于一般函数,又有一些功能之外的作用。参考了知乎上的一些回答 [2] ,小喵也进行了总结。

1、可以用表达式来定义函数,这样使得函数的定义和调用在一起,语意和逻辑上更为紧凑。同时,对于只是用一次的短小的函数,直接调用匿名的lambda表达式是最好的选择,这样就不需要给每个函数起名字了。 /* 起名字一直是一个很令人头疼的问题 */

2、闭包(Closure)。这个小喵的写javascript的时候时常会用到。闭包本质上就是能够访问上下文环境中变量的代码块。

这里我们简单的举个例子,还是之前的求阶乘的问题,现在我们有些提高需求。

现在需要完成下面的三种阶乘的运算:

n! = n * (n – 1) * (n – 2) * …

n!! = n * (n – 2) * (n – 4) * …

n!!! = n * (n – 3) * (n – 6) * …

要求编写3个函数,分别完成上述3种计算。

使用一般的方式写很容易实现,我们这里直接使用lambda表达式来实现:

#include <iostream>
#include <functional>
std::function<int(int)> getFactorialFunc(int n) {
 return [n](int x) {
  int fact = 1;
  for (; x >= 1; x -= n) fact *= x;
  return fact;
 };
}
int main() {
 // 构造要求的三个函数
 autofactorial1 = getFactorialFunc(1);
 autofactorial2 = getFactorialFunc(2);
 autofactorial3 = getFactorialFunc(3);
 // 调用
 std::cout << factorial1(10) << std::endl;
 std::cout << factorial2(10) << std::endl;
 std::cout << factorial3(10) << std::endl;
}

编译的时候要注意,lambda表达式是C++11开始支持的,所以需要指定一下C++的版本。

g++ factorial_lambda.cpp -o factorial_lambda.out --std=c++11

运行之后的结果为:

./factorial_lambda.out
3628800
3840
280

这里作为返回值的lambda表达式,可以访问先前传入的参数,这也就是闭包。具体的语法,我们后面会讲到。

3、柯里化(Currying)。这部分小喵也是第一次接触,维基百科有如下解释:

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。 [3]

下面给出一个例子(也是实现之前的阶乘):

#include <iostream>
#include <functional>
// 两个参数的阶乘
int factorial(int n, int step) {
 int r = 1;
 for (; n >= 1; n -= step) {
  r *= n;
 }
 return r;
}
// curring化的阶乘
std::function<int(int)> currying_factorial(int step) {
 return [step](int n) {
  return factorial(n, step);
 };
}
int main() {
 // 调用普通函数
 std::cout << factorial(10, 1) << std::endl;
 std::cout << factorial(10, 2) << std::endl;
 std::cout << factorial(10, 3) << std::endl;
 // 调用currying函数
 std::cout << currying_factorial(1)(10) << std::endl;
 std::cout << currying_factorial(2)(10) << std::endl;
 std::cout << currying_factorial(3)(10) << std::endl;
 return 0;
}

4、lambda表达式整体可以被当做函数的参数或者返回值。

闭包和currying的例子就是将整个lambda表达式作为返回值。现在再举一个作为参数的例子:

#include <iostream>
#include <functional>
int operate(int x, int y, const std::function<int(int, int)> &op) {
 return op(x, y);
}
int main() {
 autoadd = [](int x, int y) { return x + y;};
 automul = [](int x, int y) { return x - y;};

 std::cout << operate(10, 5, add) << std::endl;
 std::cout << operate(10, 5, mul) << std::endl;
 return 0;
}

运行的结果:

其实函数也可以当参数传入的(函数指针),但是lambda表达式要更为直观和灵活一些。谁能一眼看出int (*func(int))(int)究竟是什么意思呢(这是一个函数的定义,输入的参数是int,返回值是一个函数指针,函数指针对应的函数的输入和输出类型都是int)。

三、Lambda表达式的语法

看到前面的lambda表达式的各种有趣的功能,现在是不是非常迫切的想尝试一把?

ISO C++ 标准展示了作为第三个参数传递给 std::sort() 函数的简单 lambda:

#include <algorithm>
#include <cmath> 

void abssort(float* x, unsigned n) {
 std::sort(x, x + n,
  // Lambda expression begins
  [](float a, float b) {
   return (std::abs(a) < std::abs(b));
  } // end of lambda expression
 );
}

lambda表达式的组成部分见下图:

Capture 子句(在 C++ 规范中也称为 lambda 引导。)

参数列表(可选)。 (也称为 lambda 声明符)

可变规范(可选)。

异常规范(可选)。

尾随返回类型(可选)。

“lambda 体”

接下来我们需要学习这6个部分。

1、Capture 子句

我们知道,一般情况下,函数只能访问自己的参数和外部的全局变量。而lambda表达式却可以访问上下文的变量(参见闭包的例子)。那么如何指定要访问的变量,以及访问的方式(值或者引用)呢?这就是Capture 子句要解决的问题。

Lambda 可在其主体中引入新的变量(用 C++14),它还可以访问(或 “捕获” )周边范围内的变量。 Lambda 以 Capture 子句(标准语法中的  lambda 引导 )开头,它指定要捕获的变量以及是通过值还是引用进行捕获。 有与号 ( & ) 前缀的变量通过引用访问,没有该前缀的变量通过值访问。

空 capture 子句 [ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。

可以使用默认捕获模式(标准语法中的 capture-default )来指示如何捕获 lambda 中引用的任何外部变量:[&] 表示通过引用捕获引用的所有变量,而 [=] 表示通过值捕获它们。 可以使用默认捕获模式,然后为特定变量显式指定相反的模式。 例如,如果 lambda 体通过引用访问外部变量  total 并通过值访问外部变量  factor ,则以下 capture 子句等效:

[&total, factor] 
[factor, &total] 
[&, factor] 
[factor, &] 
[=, &total] 
[&total, =]

我们之前的闭包中使用的就是通过值访问。

使用 capture-default 时,只有 lambda 中提及的变量才会被捕获。

如果 capture 子句包含 capture-default & ,则该 capture 子句的  identifier 中没有任何  capture 可采用  & identifier 形式。 同样,如果 capture 子句包含  capture-default = ,则该 capture 子句的  capture 不能采用  = identifier 形式。 identifier 或  this 在 capture 子句中出现的次数不能超过一次。 以下代码片段给出了一些示例。

struct S { void f(int i); };
 void S::f(int i) {
 [&, i]{}; // OK
 [=, &i]{}; // OK
 [&, &i]{}; // ERROR: i preceded by & when & is the default
 [=, this]{}; // ERROR: this when = is the default
 [i, i]{}; // ERROR: i repeated
}

capture 后跟省略号是包扩展,如以下可变参数模板 [4] 示例中所示:

template<class... Args>
void f(Args... args) {
 auto x = [args...] { return g(args...); };
 x();
}

要在类方法的正文中使用 lambda 表达式,需要将this指针传递给 Capture 子句,以提供对封闭类的方法和数据成员的访问权限。

这里大家可能觉得有点奇怪,将this指针传给Capture子句?

其实我们常使用的成员函数也是用类似的方法实现的。我们知道,使用成员函数需要有一个类实例,但是调用类函数就不需要。这是因为成员函数的第一个参数是this,当然这个参数我们编写代码的时候不需要自己手动写出,而是默认的。使用像python这样的语言的时候就是需要显示的写出的。在使用类实例调用成员函数的时候,会默认将this指针传入。成员函数有这么一个参数,就可以访问类实例的各种变量和方法。而类函数是没有这个参数的,也就是没有this这个指针,因此它的调用并不需要类实例,当然也就不能访问类实例的变量。

在使用 capture 子句时,要记住以下几点(尤其是使用采取多线程的 lambda 时):

引用捕获可用于修改外部变量,而值捕获却不能实现此操作。 (mutable允许修改副本,而不能修改原始项。)

引用捕获会反映外部变量的更新,而值捕获却不会反映。

引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。 当 lambda 以异步方式运行时,这一点尤其重要。 如果在异步 lambda 中通过引用捕获本地变量,该本地变量将很可能在 lambda 运行时消失,从而导致运行时访问冲突。

通用捕获 (C++14)

在 C++14 中,可在 Capture 子句中引入并初始化新的变量,而无需使这些变量存在于 lambda 函数的封闭范围内。 初始化可以任何任意表达式表示;且将从该表达式生成的类型推导新变量的类型。 此功能的一个好处是,在 C++14 中,可从周边范围捕获只移动的变量(例如 std::unique_ptr)并在 lambda 中使用它们。

pNums = make_unique<vector<int>>(nums);
//...
  auto a = [ptr = move(pNums)]()
  {
   // use ptr
  };

2、参数列表

除了捕获变量,lambda 还可接受输入参数。 参数列表(在标准语法中称为 lambda 声明符 )是可选的,它在大多数方面类似于函数的参数列表。

autoadd = [] (int first, int second)
{
 return first + second;
};

在 C++14 中,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。 这将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 auto 实例等效于一个不同的类型参数。

autoadd = [] (autofirst, autosecond)
{
 return first + second;
};

lambda 表达式可以将另一个 lambda 表达式作为其参数。

由于参数列表是可选的,因此在不将参数传递到 lambda 表达式,并且其 lambda-declarator: 不包含  exception-specification 、 trailing-return-type 或  mutable 的情况下,可以省略空括号。

[]{}; // 这就是最简单的lambda表达式

3、可变规范

通常,lambda 的函数调用运算符为 const-by-value,但对 mutable 关键字的使用可将其取消。 它不会生成可变的数据成员。 利用可变规范,lambda 表达式的主体可以修改通过值捕获的变量。 本文后面的一些示例将显示如何使用  mutable 。

#include <iostream>
int main()
{
 int n = 10;
 autolambda1 = [n](int x) {
  /* ++ n; */ // 这句编译会出错,错误信息如下:
     // error: cannot assign to a variable captured
     // by copy in a non-mutable lambda
  return x + n;
 };
 autolambda2 = [n](int x) mutable {
  ++ n;
  return x + n;
 };
 std::cout << lambda1(5) << " " << n << std::endl;
 std::cout << lambda2(5) << " " << n << std::endl;
 return 0;
}

输出的结果是:

可以看出n确实是通过值来访问,在lambda1中,我们运行++n,在编译的时候会报错。使用mutable修饰之后,就可以修改参数(副本)的值。

4、异常规范

你可以使用 throw() 异常规范来指示 lambda 表达式不会引发任何异常。与普通函数一样,如果 lambda 表达式声明  C4297 异常规范且 lambda 体引发异常,Visual C++ 编译器将生成警告  throw() ,如下所示:

// throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{
 []() throw() { throw 5; }();
}

在MSDN的异常规范 [5] 中,明确指出异常规范是在 C++11 中弃用的 C++ 语言功能。因此这里不建议不建议大家使用。

5、返回类型

将自动推导 lambda 表达式的返回类型。 无需使用 auto 关键字,除非指定 尾随返回类型 。 trailing-return-type 类似于普通方法或函数的返回类型部分。 但是,返回类型必须跟在参数列表的后面,你必须在返回类型前面包含 trailing-return-type 关键字  -> 。

如果 lambda 体仅包含一个返回语句或其表达式不返回值,则可以省略 lambda 表达式的返回类型部分。 如果 lambda 体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。 否则,编译器会将返回类型推导为 void 。

#include <iostream>
#include <typeinfo>
int main() {
 autolambda1 = [](int i) {return i;};
 autolambda2 = [](int i) -> bool {return i;};
 autolambda3 = [](int i) -> float {return i;};
 /* auto lambda4 = []{ return {1, 2}; };*/ // ERROR: return type is void
            // cannot deduce lambda return type

 autox1 = lambda1(10);
 autox2 = lambda2(10);
 autox3 = lambda3(10);

 std::cout << x1 << " " << typeid(x1).name() << std::endl;
 std::cout << x2 << " " << typeid(x2).name() << std::endl;
 std::cout << x3 << " " << typeid(x3).name() << std::endl;
 return 0;
}

typeinfo的功能是获取一个变量的类型,由于它的实现依赖于编译器,所以在不同平台下的输出可能不完全一样。小喵这边的输出是:

10 i
1 b
10 f

可以看出,三个lambda的输出是不相同的。默认情况下,会返回一个最直接的类型。

6、lambda体

lambda体其实和函数体几乎完全相同。

lambda 表达式的 lambda 体(标准语法中的 compound-statement )可包含普通方法或函数的主体可包含的任何内容。 普通函数和 lambda 表达式的主体均可访问以下变量类型:

从封闭范围捕获变量,如前所述(Capture)。

参数

本地声明变量

类数据成员(在类内部声明并且捕获  this  时)

具有静态存储持续时间的任何变量(例如,全局变量)

这里要注意我们在Capture 规范中说到的值访问和引用访问的特点。

下面的例子都是MSDN上给出的。

以下示例包含通过值显式捕获变量 n 并通过引用隐式捕获变量  m 的 lambda 表达式:

// captures_lambda_expression.cpp
// compile with: /W4 /EHsc
#include <iostream>
using namespace std;
int main()
{
 int m = 0;
 int n = 0;
 [&, n] (int a) mutable { m = ++n + a; }(4);
 cout << m << endl << n << endl;
}

输出结果:

5

0

由于变量 n 是通过值捕获的,因此在调用 lambda 表达式后,变量的值仍保持  0 不变。   mutable 规范允许在 lambda 中修改  n 。

尽管 lambda 表达式只能捕获具有自动存储持续时间的变量,但你可以在 lambda 表达式的主体中使用具有静态存储持续时间的变量。 以下示例使用 generate 函数和 lambda 表达式为  vector 对象中的每个元素赋值。 lambda 表达式将修改静态变量以生成下一个元素的值。

void fillVector(vector<int>& v)
{
 // A local static variable.
 static int nextValue = 1; 

 // The lambda expression that appears in the following call to
 // the generate function modifies and uses the local static
 // variable nextValue.
 generate(v.begin(), v.end(), [] { return nextValue++; });
 //WARNING: this is not thread-safe and is shown for illustration only
}

四、应用Lambda的比较函数的编写

为什么要补充这一部分呢?因为我们在写程序的时候,往往最常用到lambda的地方就是数组的sort。

首先,我们知道std::sort默认是接受2个参数的,表示需要排序的序列的开始和结尾。对于一些复杂的数据类型,我们可以给它添加一个用来比较的函数 operator <。但更多的是通过给sort添加第三个参数来实现。而这个参数就是一个比较器。

sort默认使用<比较符来进行比较,排序的结果是升序。我们写的比较函数的功能就是代替<。记住这个特点,就不会在编写比较函数的时候理不清思路。

这里举一个小例子,给一组点坐标,按欧氏距离排序:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
 vector< pair<int, int> > arr;
 arr.push_back(make_pair(1, 4));
 arr.push_back(make_pair(2, 3));
 arr.push_back(make_pair(5, 7));
 arr.push_back(make_pair(6, 2));

 sort(arr.begin(), arr.end(),
  [](pair<int, int> left, pair<int, int> right) {
   int d1 = left.first * left.first + left.second * left.second;
   int d2 = right.first * right.first + right.second * right.second;
   return d1 < d2;
  });

 for (auto &p: arr) {
  cout << "(" << p.first << ", " << p.second << ")" << endl;
 }
 return 0;
}

输出结果:

(2, 3)
(1, 4)
(6, 2)
(5, 7)

唯一需要注意的是,我们的比较函数取代的是<。

PS:

lambda 怎么传递ref参数

ambda 传递ref参数有个语法bug,必须要显式书写参数类型。

//如
delegate bool FuncType(ref int num);
FuncType func1;
func1 = num => true; //错
func1 = (ref num) => true;//错
func1 = (ref int num) => true;//ok
//并且,当一个参数书写类型,其他参数也要书写,总之很烦。

以上所述是小编给大家介绍的C++ 中的Lambda表达式写法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 基于C++ Lambda表达式的程序优化

    什么是Lambda? C++ 11加入了一个非常重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,许多人多block情有独钟,将各种回调函数.代理通通都用它来实现.甚至有人选择用FBKVOController.BlocksKit等开源框架将KVO.控件事件处理都改为通过block解决.原因就是简单.方便.直观,函数的定义和使用出现在同一个地方.这里的Lambda表达式实际上和block非常类似,当然如果你用它和Swift语言的闭包比较,那就是一回事了. 这是

  • 结合C++11新特性来学习C++中lambda表达式的用法

    在 C++ 11 中,lambda 表达式(通常称为 "lambda")是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法. Lambda 通常用于封装传递给算法或异步方法的少量代码行. 本文定义了 lambda 是什么,将 lambda 与其他编程技术进行比较,描述其优点,并提供一个基本示例. Lambda 表达式的各部分 ISO C++ 标准展示了作为第三个参数传递给 std::sort() 函数的简单 lambda: #include <algorit

  • C++中的Lambda表达式详解

    我是搞C++的 一直都在提醒自己,我是搞C++的:但是当C++11出来这么长时间了,我却没有跟着队伍走,发现很对不起自己的身份,也还好,发现自己也有段时间没有写C++代码了.今天看到了C++中的Lambda表达式,虽然用过C#的,但是C++的,一直没有用,也不知道怎么用,就可怜的连Lambda语法都看不懂.好了,这里就对C++中的Lambda进行一个简单的总结,就算是对自己的一个交代,我是搞C++的,我是一个C++ programmer. 一段简单的Code 我也不是文艺的人,对于Lambda的

  • C++ 中lambda表达式的编译器实现原理

    什么是Lambda? C++ 11加入了一个非常重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,许多人多block情有独钟,将各种回调函数.代理通通都用它来实现.甚至有人选择用FBKVOController.BlocksKit等开源框架将KVO.控件事件处理都改为通过block解决.原因就是简单.方便.直观,函数的定义和使用出现在同一个地方.这里的Lambda表达式实际上和block非常类似,当然如果你用它和Swift语言的闭包比较,那就是一回事了. 现在

  • 实例讲解C++编程中lambda表达式的使用

    函数对象与Lambdas 你编写代码时,尤其是使用 STL 算法时,可能会使用函数指针和函数对象来解决问题和执行计算.函数指针和函数对象各有利弊.例如,函数指针具有最低的语法开销,但不保持范围内的状态,函数对象可保持状态,但需要类定义的语法开销. lambda 结合了函数指针和函数对象的优点并避免其缺点.lambda 与函数对象相似的是灵活并且可以保持状态,但不同的是其简洁的语法不需要显式类定义. 使用lambda,相比等效的函数对象代码,您可以写出不太复杂并且不容易出错的代码. 下面的示例比较

  • 浅析C++11新特性的Lambda表达式

    lambda简介 熟悉Python的程序员应该对lambda不陌生.简单来说,lambda就是一个匿名的可调用代码块.在C++11新标准中,lambda具有如下格式: [capture list] (parameter list) -> return type { function body } 可以看到,他有四个组成部分: 1.capture list: 捕获列表 2.parameter list: 参数列表 3.return type: 返回类型 4.function body: 执行代码

  • 浅谈C++11新引入的lambda表达式

    ISO C++ 11 标准的一大亮点是引入Lambda表达式.基本语法如下: [capture list] (parameter list) ->return type { function body } 简单的讲一下各个部分的作用 1.[capture list]捕获列表,捕获到函数体中,使得函数体可以访问 2.(parameter list)参数列表,用来表示lambda表达式的参数列表 3.->return type函数返回值 {function body}就是函数体 lambda表达式

  • C++ 中的Lambda表达式写法

    小喵的唠叨话: 寒假之后,小喵在家里无所事事,最近用C++写代码的时候,用到了std::sort这个函数,每次用这个函数,小喵似乎都得查一下lambda表达式的写法.正好最近很闲,不如总结一下. 在Bing上搜索 C++ lambda ,第一条记录就是MSDN上的C++ lambda的介绍.本文也是基于这篇文章来写的. 那么接下来,我们分几个部分来介绍. 一.什么是Lambda表达式 MSDN上对lambda表达式的解释: 在 C++ 11 中,lambda 表达式(通常称为 "lambda&q

  • Java8中的 Lambda表达式教程

     1. 什么是λ表达式 λ表达式本质上是一个匿名方法.让我们来看下面这个例子: public int add(int x, int y) { return x + y; } 转成λ表达式后是这个样子: (int x, int y) -> x + y; 参数类型也可以省略,Java编译器会根据上下文推断出来: (x, y) -> x + y; //返回两数之和 或者 (x, y) -> { return x + y; } //显式指明返回值 可见λ表达式有三部分组成:参数列表,箭头(-&g

  • Java8中的lambda表达式入门教程

    1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public String getName() { ret

  • 深入理解Java中的Lambda表达式

    Java 8 开始出现,带来一个全新特性:使用 Lambda 表达式 (JSR-335) 进行函数式编程.今天我们要讨论的是 Lambda 的其中一部分:虚拟扩展方法,也叫做公共辩护(defender)方法.该特性可以让你在接口定义中提供方法的默认实现.例如你可以为已有的接口(如 List 和 Map)声明一个方法定义,这样其他开发者就无需重新实现这些方法,有点像抽象类,但实际却是接口.当然,Java 8 理论上还是兼容已有的库. 虚拟扩展方法为 Java 带来了多重继承的特性,尽管该团队声称与

  • 详解Java中的Lambda表达式

    简介 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块). Lambda表达式还增强了集合库. Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及java.util.stream 包. 流(stream)就如同迭代器(iterator),但附加了许多额外的功能.

  • python中的lambda表达式用法详解

    本文实例讲述了python中的lambda表达式用法.分享给大家供大家参考,具体如下: 这里来为大家介绍一下lambda函数. lambda 函数是一种快速定义单行的最小函数,是从 Lisp 借用来的,可以用在任何需要函数的地方 .下面的例子比较了传统的函数定义def与lambda定义方式: >>> def f ( x ,y): ... return x * y ... >>> f ( 2,3 ) 6 >>> g = lambda x ,y: x *

  • Android Studio中使用lambda表达式的方法

    1.module的build.gradle里buildTypes中添加: compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } 2.module的build.gradle里defaultConfig中添加: jackOptions.enabled = true 3.注意事项:jack可能会导致中文乱码,所以需要在gradle.proper

  • Android Studio中引入Lambda表达式的方法

    本文介绍的是在Android Studio中引入Lambda表达式的方法,下面话不多说,来看看详细的介绍. 方法如下: 依次点击 [File][Other Settings][Default Project Structure]确保当前项目使用的JDK版本是1.8. 打开项目(Project)的build.gradle,在dependencies节点添加 classpath 'me.tatarka:gradle-retrolambda:3.2.0' 打开项目(Module)的build.grad

  • 初步认识C#中的Lambda表达式和匿名方法

    写在前面 元旦三天在家闲着无事,就看了看Linq的相关内容,也准备系统的学习一下,作为学习Linq的前奏,还是先得说说Lambda与匿名方法的知识点.也算是对知识点的查漏补缺吧,也许你会说这没啥大不了的,项目中都在用,但是有些知识,你回头在查看的时候,总会有那么点不一样的收获,这点我是感同身受的,我看书有个习惯,一本书,我能看个三四遍,每次总会有收获.当然,你可以说,当时肯定没认真看,不是那样子的,我认为最直接的原因在于,当时你看是看,没有在真正的项目中遇到过,所以你心里对它的理解并不深,如果在

随机推荐