经常在技术博客中看到匿名函数、闭包函数和 lambda 表达式这样名词,但一直傻傻分不清他们之间究竟有什么区别,所以想一探究竟。
函数定义
一个函数的定义,一般会包含:函数名、函数的参数、函数的主体(代码块)、函数的返回类型/值。
1 | func hello(name string) string { |
闭包函数
通过字面意思理解,即定义在内部的函数。
1 | package main |
- 执行 test()函数返回闭包函数。
- 执行闭包函数发现可以使用 x 变量,但不用声明 x 变量。
- 再次执行闭包函数仍旧可以使用 x 变量,说明闭包函数自身在“维护”x 变量。
- 通过内存地址可以看出闭包函数和 test()函数的 x 变量是同一个变量。
是不是可以理解为:
函数创建时获取所需外部状态,即使外部状态关闭,函数中的状态还会存在。这个过程就是“闭包”,或许闭包函数解决的是变量作用域的问题?
引用 JavaScript MDN 对闭包函数的一句解释:
A closure is the combination of a function and the lexical environment within which that function was declared.
匿名函数
匿名函数,即“无名”函数。
1 | package main |
匿名函数可以直接定义在代码块中。匿名函数可以减少函数暴露,防止被外部代码调用执行(避免数据污染)。
lambda“函数”
lambda“函数”,严格来说应该叫 lambda 表达式。它是一个可以接受 N 个参数但只返回单个表达式值的“函数”,可以理解为它是匿名函数的一种代码风格或者语法糖。
lambda 会使代码看起来比较简洁,很适用于这个函数“只用一次”的场景。比如:
1 | def square(x): |
lambda 表达式带来代码简洁的同时也有副作用,lambda 可读性较差,不适用于很长很复杂的逻辑,所以不要为了写 lambda 而写 lambda。
1 | func = lambda x, y, z: x + y + z |
在Visual Studio Code
中编辑保存这段代码会被自动转换,在PyCharm
中则会直接给出警告PEP 8: E731 do not assign a lambda expression, use a def
autopep8
至于为什么这种书写方式称之为 lambda 表达式,则是有原因的:
Alonzo Church 在 30 年代发明的Lambda Calculus,你可以在其中做的一件事就是 λ 运算。
最后
猜猜以下这段代码执行后会输出什么?
1 | package main |