Lambda Function (C++, Java, Python)

4 篇文章 0 订阅
1 篇文章 0 订阅

Lambda Function

Definition

Lambda函数也被称为匿名(没有名称)函数,它直接接受参数的数量以及使用该参数执行的条件或操作,该参数以冒号分隔,并返回最终结果。为了在大型代码库上编写代码时执行一项小任务,或者在函数中执行一项小任务,便在正常过程中使用lambda函数。

For C++,

C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作
Lambda 语法形式:

[capture](parameters) mutable ->return-type{statement}

[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}。可以看到,Lambda 主要分为五个部分:[函数对象参数]、(操作符重载函数参数)、mutable 或 exception 声明、-> 返回值类型、{函数体}.

(1) [capture][函数对象参数]:标识一个 Lambda 表达式的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this,通俗:主函数的局部变量等)。函数对象参数有以下形式:

[]。没有任何函数对象参数。
[=]。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
[&]。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于是编译器自动为我们按引用传递了所有局部变量)。
[this]。函数体内可以使用 Lambda 所在类中的成员变量。
[a]。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要修改传递进来的拷贝,可以添加 mutable 修饰符。
[&a]。将 a 按引用进行传递。
[a,&b]。将 a 按值传递,b 按引用进行传递。
[=,&a,&b]。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
[&,a,b]。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。
注意:值传递,在lambda函数定义时就确定了,不会随lambda引用改变。

(2) (parameters)(操作符重载函数参数):标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。

(3) mutable 或 exception 声明:这部分可以省略。按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。

(4) ->return-type-> 返回值类型:标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

(5) {statement}{函数体}:标识函数的实现,这部分不能省略,但函数体可以为空。

For Java,

匿名内部类会创建 class 文件,lambda 只能用于单个抽象方法的接口

java8 的 lambda 引入了两个核心思想:
方法引用
行为参数化 把一个方法作为参数传递给另一个方法

所以很多时候为了明确的标注出你是一个函数式接口,往往会在接口上面增加一行注释@functionalInterface。但是,默认方法和静态方法不会破坏函数式接口的定义。

之所以在JDK1.8之后提供有默认和静态方法,也都是为函数式开发做准备。

Lambda表达式的几种格式
方法没有参数: () -> {};

方法有参数::(参数,…,参数) -> {};

使用Lambda表达式(无参)

要创建接口 IMessage 的实现类,如果该类只是使用一次,我们可以使用匿名内部类的方式,但是匿名内部类写起来很麻烦。而 IMessage 接口中,只有一个抽象方法,是一个函数式接口,那么我们就可以使用 lambda 来代替匿名内部类。lambda 体就是接口的实现。

@FunctionalInterface
interface IMessage {
    public void send();
}

public class JavaDemo {
    public static void main(String[] args) {
        IMessage i = () -> System.out.println("www.baidu.com");
        i.send();
    }
}

注:抽象方法如果没有参数,则 lambda 表达式不能省略 ();

使用Lambda表达式(有参)

IMath 接口中只有一个抽象方法,该方法有返回值,且有两个参数。可以使用 lambda 进行简化。

@FunctionalInterface
interface IMath {
    public int add(int x, int y);
}

public class JavaDemo {
    public static void main(String[] args) {
    	// t1,t2是形参名,随便取,但是个数必须匹配形参
        IMath math = (t1, t2) -> { 
            return t1 + t2;
        };
        System.out.println(math.add(20, 30));
    }
}

以上的表达式之中你会发现只有一行语句“ return t1 + t2;”,这时候可以进一步简化。
使用Lambda表达式简化(再度简化Lambda表达式,把return语句也省略)

@FunctionalInterface
interface IMath{
	public int add(int x , int y);
}
public class Demo01 {
		IMath math = (n1,n2)-> n1 + n2;
		System.out.println(math.add(10,20));
	}
	
}

Conclusion

lambda 表达式形式为 ()->{},-> 左边是抽象方法的形参列表, -> 是抽象方法的实现体。
lambda 方法如果没有参数或有两个及以上的参数,则 小括号不能省略。
lambda 方法如果只有一个参数,则小括号可以省略。
lambda 方法体如果只有一行语句,则 大括号和return都可省略。
省略了大括号,则必须省略 return,省略了 return ,则必须省略 {},这俩要么成对出现,要么都不出现。

lambda 的本质就是函数式接口的一个实现类。

eg:
/**
 * 通过 lambda 表达式优化代码
 */
@Test
public void t2(){
    int[] a = {1,2,3,4};
    ProcessArray processArray = new ProcessArray();
    processArray.process(a, target -> {
        int sum = 0;
        for (int i : target) {
            sum += i;
        }
        log.info("数组和为{}", sum);
    });
}
For Python,

lambda语法形式:

lambda argument_list: expression

其中,lambda是Python预留的关键字,argument_list和expression由用户自定义。具体介绍如下。

  1. 这里的argument_list是参数列表,它的结构与Python中函数(function)的参数列表是一样的。具体来说,argument_list可以有非常多的形式。例如:

a, b
a=1, b=2
*args
**kwargs
a, b=1, *args


2. 这里的expression是一个关于参数的表达式。表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的。以下都是合法的表达式:

1
None
a + b
sum(a)
1 if a >10 else 0

3. 这里的lambda argument_list: expression表示的是一个函数。这个函数叫做lambda函数。

Characteristic

lambda函数有如下特性:

lambda函数是匿名的:所谓匿名函数,通俗地说就是没有名字的函数。lambda函数没有名字。

lambda函数有输入和输出:输入是传入到参数列表argument_list的值,输出是根据表达式expression计算得到的值。

lambda函数一般功能简单:单行expression决定了lambda函数不可能完成复杂的逻辑,只能完成非常简单的功能。由于其实现的功能一目了然,甚至不需要专门的名字来说明。

下面是一些lambda函数示例:

  lambda x, y: x*y;函数输入是x和y,输出是它们的积x*y
 lambda:None;函数没有输入参数,输出是None
 lambda *args: sum(args); 输入是任意个数的参数,输出是它们的和(隐性要求是输入参数必须能够进行加法运算)
 lambda **kwargs: 1;输入是任意键值对参数,输出是1

Cases

由于lambda语法是固定的,其本质上只有一种用法,那就是定义一个lambda函数。在实际中,根据这个lambda函数应用场景的不同,可以将lambda函数的用法扩展为以下几种:

将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。

例如,执行语句add=lambda x, y: x+y,定义了加法函数lambda x, y: x+y,并将其赋值给变量add,这样变量add便成为具有加法功能的函数。例如,执行add(1,2),输出为3。

将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。

例如,为了把标准库time中的函数sleep的功能屏蔽(Mock),我们可以在程序初始化时调用:time.sleep=lambda x:None。这样,在后续代码中调用time库的sleep函数将不会执行原有的功能。例如,执行time.sleep(3)时,程序不会休眠3秒钟,而是什么都不做。

  3. 将lambda函数作为其他函数的返回值,返回给调用者。

函数的返回值也可以是函数。例如return lambda x, y: x+y返回一个加法函数。这时,lambda函数实际上是定义在某个函数内部的函数,称之为嵌套函数,或者内部函数。对应的,将包含嵌套函数的函数称之为外部函数。内部函数能够访问外部函数的局部变量,这个特性是闭包(Closure)编程的基础,在这里我们不展开。

  4. 将lambda函数作为参数传递给其他函数。

部分Python内置函数接收函数作为参数。典型的此类内置函数有这些。

filter函数。此时lambda函数用于指定过滤列表元素的条件。例如filter(lambda x: x % 3 == 0, [1, 2, 3])指定将列表[1,2,3]中能够被3整除的元素过滤出来,其结果是[3]。

sorted函数。此时lambda函数用于指定对列表中所有元素进行排序的准则。例如sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))将列表[1, 2, 3, 4, 5, 6, 7, 8, 9]按照元素与5距离从小到大进行排序,其结果是[5, 4, 6, 3, 7, 2, 8, 1, 9]。

map函数。此时lambda函数用于指定对列表中每一个元素的共同操作。例如map(lambda x: x+1, [1, 2,3])将列表[1, 2, 3]中的元素分别加1,其结果[2, 3, 4]。

reduce函数。此时lambda函数用于指定列表中两两相邻元素的结合条件。例如reduce(lambda a, b: ‘{}, {}’.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])将列表 [1, 2, 3, 4, 5, 6, 7, 8, 9]中的元素从左往右两两以逗号分隔的字符的形式依次结合起来,其结果是’1, 2, 3, 4, 5, 6, 7, 8, 9’。

另外,部分Python库函数也接收函数作为参数,例如gevent的spawn函数。此时,lambda函数也能够作为参数传入。

Argument

事实上,关于lambda在Python社区是存在争议的。Python程序员对于到底要不要使用lambda意见不一致。

支持方认为使用lambda编写的代码更紧凑,更“pythonic”。

反对方认为,lambda函数能够支持的功能十分有限,其不支持多分支程序if…elif…else…和异常处理程序try …except…。并且,lambda函数的功能被隐藏,对于编写代码之外的人员来说,理解lambda代码需要耗费一定的理解成本。他们认为,使用for循环等来替代lambda是一种更加直白的编码风格。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cmy_CTO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值