Lua程序设计(5)

Lua中的闭包。

闭包

在Lua语言中,函数是严格遵循词法定界的第一类值。

“第一类值”意味着Lua语言中的函数与与其他常见类型的值具有同等权限(函数也是值):

  • 一个程序可以将某个函数保存到变量中或表中
  • 可以将某个函数作为参数传递给其他函数
  • 还可以将某个函数作为其他函数的返回值返回。

“词法定界”意味着Lua语言中的函数可以访问包含其自身的外部函数中的变量。

函数是第一类值:

Lua中常见的函数定义方式如下:

1
2
3
function foo(x) return 2*x end -- 语法糖
-- 等同于
foo = function(x) return 2*x end

赋值语句右边的表达式就是函数构造器。

在Lua语言中,所有的函数都是匿名的,像其他所有的值一样,函数并没有名字,在讨论函数名时,实际上指的是保存该函数的变量名

以另一个函数为参数的函数,称为高阶函数(例如函数sort)。高阶函数是一种强大的编程机制,而利用匿名函数作为参数正是其灵活性的来源。

非全局函数

函数不仅可以被存储在全局变量中,还可以被存储在表字段和局部变量中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 几种存储在表字段中的写法
Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end

-- 表构造器
Lib = {
foo = function (x,y) return x + y end
goo = function (x,y) return x - y end
}

-- 一种特殊的语法
Lib = {}
function Lib.foo (x,y) return x + y end
function Lib.goo (x,y) return x - y end

当把一个函数存储到局部变量中,就得到了一个局部函数,即一个被限定在指定作用域中使用的函数。由于Lua语言将每个程序段作为一个函数处理,所以在一段程序中声明的函数就是局部函数,这些局部函数只在该程序段中可见。

词法定界

当编写一个被其他函数B包含的函数A时,被包含的函数A可以访问包含其的函数B的所有全局变量。

假入想建立一个函数来对学生姓名排序,可以:

1
2
3
4
5
function sortbygrade(names,grades)
table.sort(names,function(n1,n2)
return grades[n1] > grades[n2]
end)
end

注意:传给函数sort的匿名函数可以访问grades,而grades是包含匿名函数的外层函数sortbygrades的形参,在该匿名函数中,grades既不是全局变量,也不是局部变量,而是非全局变量,也称上值(upvalue)。

函数作为第一类值,能够逃逸出它们变量的原始定界范围。

简单的说,一个闭包就是一个函数外加能够使该函数正确访问非局部变量所需的其他机制