非全局函数

简介: 非全局函数

由于函数以一种第一类值,因此一个显而易见的结果就是:函数不仅可以被存储在全局变量中,还可以被存储在表字段和局部变量中。


大部分 Lua 语言的库都是采用了将函数存储在表字段中的方式,例如: io.readmath.sin 。如下所示:

lib = {}
lib.foo = function (x, y) return x + y end
lib.goo = function (x, y) return x - y end
print(lib.foo(2, 3), lib.goo(2, 3))         --> 5     -1


当然,也可以使用表构造器:

lib = {
  foo = function (x, y) return x + y end,
  goo = function (x, y) return x - y end
}


除此之外, Lua 语言还提供了另一种特殊的语法来定义这类函数:

lib = {}
function lib.foo (x, y) return x + y end
function lib.goo (x,y ) return x - y end


提示

在表字段中存储函数是 Lua 语言中实现面向对象编程的关键要素。


当把一个函数存储到局部变量时,就得到了一个局部变量,即一个被限定在指定作用域中使用的函数。局部函数对于包而言尤其有用:由于 Lua 语言将每个程序段作为一个函数处理,所以在一段程序中声明的函数就是局部函数,这些局部函数只在该程序段中可见。词法定界保证了程序段中的其他函数可以使用这些局部函数。


对于这种几部函数的使用, Lua 语言提供了一种语法糖:

local function f (params)
  body
end


在定义局部递归函数时,由于原来的方法不适用,所以有一点是极容易出错的,考虑如下代码:

local fact = function (n)
  if n == 0 then return 1
  else return n * fact(n-1)   -- 有问题
  end
end


Lua 语言编译函数体中的 fact(n-1) 调用时,局部函数 fact 尚未定义。因此,这个表达式会尝试调用全局的 fact 而非局部的 fact 。我们可以通过先定义局部变量再定义函数的方式来解决这个问题:

local fact
fact = function (n)
  if n == 0 then return 1
  else return n * fact(n-1)   -- 没有问题
  end
end


这样,函数内的 fact 指向的是局部变量。尽管在定义函数时,这个局部变量的值尚未确定,但到了执行函数时, fact 肯定已经有了正确的赋值。


Lua 原因展开局部函数的语法糖时,使用的并不是之前的基本函数定义。相反,形如:

local function foo (params) body end


的定义会被展开成:

local foo; foo = function (params) body end


因此,使用这种语法来定义递归函数不会有问题。


当然,这个技巧对于间接递归函数是无效的。在间接递归的情况下,必须使用与明确的前向声明等价的形式:

local f   -- "前向"声明
local function g ()
  some code f() some code
end
function f ()
  some code g() some code
end


注意

不能在最后一个函数定义前加上 local 。否则, Lua 语言会创建一个全新的局部变量 f ,从而使得先前声明的 f (函数 g 中使用的那个)变为未定义状态。

目录
相关文章
|
7月前
|
C++ 开发者
43运算符重载函数作为类成员函数和友元函数
43运算符重载函数作为类成员函数和友元函数
31 0
|
7月前
|
编译器 C++
c++重载函数和重载运算符
c++重载函数和重载运算符
37 0
|
7月前
|
C++ 编译器
|
7月前
|
程序员 编译器 C++
c++重载运算符和重载函数
c++重载运算符和重载函数
37 1
|
7月前
|
C++
C++程序中的类成员函数
C++程序中的类成员函数
51 1
|
7月前
友元函数、成员函数和普通函数使用上的不同
友元函数、成员函数和普通函数使用上的不同
26 0
|
编译器 C++
C++ 重载函数
C++ 重载函数
57 0
|
存储 编译器 C++
拷贝构造函数和运算符重载(上)
拷贝构造函数和运算符重载(上)
|
编译器
拷贝构造函数和运算符重载(下)
拷贝构造函数和运算符重载(下)
|
编译器 C++
C++的重载运算符和重载函数
C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。 当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。 C++ 中的函数重载 在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。 下面的实例中,同名函数print