分享
 
 
 

2.5.8 – 函数定义

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

2.5.8 – 函数定义

函数定义的语法是

function ::= function funcbody

funcbody ::= `(´ [parlist1] `)´ block end

下面的甜心语法简化了函数的定义:

stat ::= function funcname funcbody

stat ::= local function Name funcbody

funcname ::= Name {`.´ Name} [`:´ Name]

语句

function f () ... end

可翻译为

f = function () ... end

语句

function t.a.b.c.f () ... end

可翻译为

t.a.b.c.f = function () ... end

语句

local function f () ... end

可翻译为

local f; f = function () ... end

函数是可以执行的表达式,其值类型是function.当Lua预编译一个块时,所有它的函数体也被编译了。之后,无论何时Lua执行该函数定义,函数都被实例化(或者封闭)。这个函数实例(或者闭包)就是表达式的最终值。同一个函数的不同实例可能会引用到不同的外部局部变量并可能有不同的环境表。

形参作为局部变量由实参值初始化:

parlist1 ::= namelist [`,´ `...´]

parlist1 ::= `...´

当函数被定义时,实参列表被调整为形参列表的长度,除非该函数是variadic或变参函数,此种函数通过在其形参列表后面加三个点号(`...´)来标识。变参函数不会调整其形参列表,而是将所有额外的参数收集在一个称作arg的隐含参数中。arg的值是表,用一个表域n来保存额外参数的个数,并将这些参数保存在1,2,…,n的位置。

考虑下面例子中的定义:

function f(a, b) end

function g(a, b, ...) end

function r() return 1,2,3 end

之后,我们便有了下面的从实参到形参的映射:

CALL PARAMETERS

f(3) a=3, b=nil

f(3, 4) a=3, b=4

f(3, 4, 5) a=3, b=4

f(r(), 10) a=1, b=10

f(r()) a=1, b=2

g(3) a=3, b=nil, arg={n=0}

g(3, 4) a=3, b=4, arg={n=0}

g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}

g(5, r()) a=5, b=1, arg={2, 3; n=2}

结果通过return语句返回(参见2.4.4)。如果程序执行到函数末端而没有遇到return语句,则函数将不返回结果。

冒号语法用来定义方法,即,拥有一个叫作self的隐含参数的函数。因此,语句

function t.a.b.c:f (...) ... end

是下面语句的甜心语法

t.a.b.c.f = function (self, ...) ... end

2.6 – 可见性规则Lua是一种lexically scoped语言。参数的作用域从其被声明后的第一条语句开始,到其声明所在的最内层block的末尾结束。例如:

x = 10 -- 全局变量

do -- 新的block

local x = x -- 新的`x', 值为10

print(x) --> 10

x = x+1

do -- 另一个block

local x = x+1 -- 另一个`x'

print(x) --> 12

end

print(x) --> 11

end

print(x) --> 10 (全局x)

注意,在local x = x这样的声明中,被声明的新x还不在其作用域内,而第二个x引用的是一个外部变量。

由于lexical scoping规则,局部变量可被定义在其作用域内的函数自由访问,例如:

local counter = 0

function inc (x)

counter = counter + x

return counter

end

由一个内部函数使用的局部变量,在这个函数内部被称作上值,或者外部局部变量。

注意每次执行一条局部语句都会定义新的局部变量。考虑下面的例子:

a = {}

local x = 20

for i=1,10 do

local y = 0

a[i] = function () y=y+1; return x+y end

end

循环创建了十个闭包(即十个匿名函数的实例)。每个闭包都使用一个不同的y变量,而它们都共用一个x。

2.7 - 错误处理因为Lua是一个扩展语言,所有的Lua动作都从其宿主程序里调用一个Lua库中的函数的C代码开始。在Lua编译或执行时若产生错误,控制会被返回给C,由它来作适当的处理(例如打印一个错误消息)。

Lua代码可以通过调用error函数显式的产生一个错误(参见5.1)。如果你需要捕获Lua中的错误,你可以使用pcall函数(参见5.1)。

2.8 – 元表Lua中每个表和userdata对象都可以有一个元表(metatable)。元表是一个普通的Lua表,其中定义了原始表和userdata在特定操作下的行为。你可以通过设定一个对象的元表中的特定域来改变该对象的一些行为面貌。例如,当对象是加法操作的操作数时,Lua会检查它的元表中“__add”域对应的函数。如果找到了,Lua便调用那个函数来执行加法。

我们将元表中的键称作事件(events),值称作元方法(metamethods)。在上一个例子中,事件是“add”,元方法是执行加法操作的函数。

你可以通过set/getmetatable函数来查询和更改一个对象的元表(参见5.1)。

元表可以控制一个对象的在算术运算、次序比较运算、连接和索引时的行为。元表也可以定义userdata对象被作为垃圾回收时调用的函数。对上述的每一种操作Lua都为之关联了一个特定的键,称作事件。当Lua为一个表或者userdata执行那些操作时,它会检查对象是否有一个包含相应事件的元表。如果是,与该键关联的值(元方法)将控制Lua如果执行操作。

元表控制下面列出的操作。每个操作都由其对应的名字来标识。每个操作的键是以双下划线为前缀加上其名字组成的字符串;例如,“add”操作的键是“__add”。这些操作的语意用一个描述解释器如何执行它们的Lua函数作了更好的说明。

这里显示的Lua代码只是说明性的;其真实行为已被硬编码在解释器中,并且比这里的模拟代码高效许多。以下说明中用到的所有函数(rawget, tonumber, 等等)都在5.1中作了说明。特别地,要获得一个给定对象的元方法,我们使用下面的语句

metatable(obj)[event]

这可以被读作

rawget(metatable(obj) or {}, event)

即,对元方法的访问不会调用其它的元方法,对没有元表的对象的访问也不会失败(只是简单地返回nil)。

"add": the + operation. + 操作下面的getbinhandler函数定义了Lua如何为一个二元操作符选择处理函数。首先,Lua尝试第一个操作数。如果它的类型并没有为该操作定义处理函数,Lua便尝试第二个操作数。

function getbinhandler (op1, op2, event)

return metatable(op1)[event] or metatable(op2)[event]

end

使用那个函数,op1 + op2的行为便是

function add_event (op1, op2)

local o1, o2 = tonumber(op1), tonumber(op2)

if o1 and o2 then -- both operands are numeric?

return o1 + o2 -- `+' here is the primitive `add'

else -- at least one of the operands is not numeric

local h = getbinhandler(op1, op2, "__add")

if h then

-- call the handler with both operands

return h(op1, op2)

else -- no handler available: default behavior

error("...")

end

end

end

"sub": - 操作。行为与“add”操作相似。"mul": * 操作。行为与“add”操作相似。"div": / 操作。行为与“add”操作相似。"pow": ^ (求幂) 操作. function pow_event (op1, op2)

local o1, o2 = tonumber(op1), tonumber(op2)

if o1 and o2 then -- both operands are numeric?

return __pow(o1, o2) -- call global `__pow'

else -- at least one of the operands is not numeric

local h = getbinhandler(op1, op2, "__pow")

if h then

-- call the handler with both operands

return h(op1, op2)

else -- no handler available: default behavior

error("...")

end

end

end

"unm": 一元 – 操作。 function unm_event (op)

local o = tonumber(op)

if o then -- operand is numeric?

return -o -- `-' here is the primitive `unm'

else -- the operand is not numeric.

-- Try to get a handler from the operand

local h = metatable(op).__unm

if h then

-- call the handler with the operand and nil

return h(op, nil)

else -- no handler available: default behavior

error("...")

end

end

end

"concat": .. (连接) 操作. function concat_event (op1, op2)

if (type(op1) == "string" or type(op1) == "number") and

(type(op2) == "string" or type(op2) == "number") then

return op1 .. op2 -- primitive string concatenation

else

local h = getbinhandler(op1, op2, "__concat")

if h then

return h(op1, op2)

else

error("...")

end

end

end

"eq": == 操作。getcomphandler函数定义了Lua如何为比较操作符选择元方法。只有当两个被比较的对象是相同类型且其对选定操作的元方法相同时,该元方法才被选中。

function getcomphandler (op1, op2, event)

if type(op1) ~= type(op2) then return nil end

local mm1 = metatable(op1)[event]

local mm2 = metatable(op2)[event]

if mm1 == mm2 then return mm1 else return nil end

end

“eq”事件的定义如下:

function eq_event (op1, op2)

if type(op1) ~= type(op2) then -- different types?

return false -- different objects

end

if op1 == op2 then -- primitive equal?

return true -- objects are equal

end

-- try metamethod

local h = getcomphandler(op1, op2, "__eq")

if h then

return h(op1, op2)

else

return false

end

end

a ~= b 等价于 not (a == b).

"lt": < 操作。function lt_event (op1, op2)

if type(op1) == "number" and type(op2) == "number" then

return op1 < op2 -- numeric comparison

elseif type(op1) == "string" and type(op2) == "string" then

return op1 < op2 -- lexicographic comparison

else

local h = getcomphandler(op1, op2, "__lt")

if h then

return h(op1, op2)

else

error("...");

end

end

end

a > b 等价于 b < a.

"le": the <= operation. function le_event (op1, op2)

if type(op1) == "number" and type(op2) == "number" then

return op1 <= op2 -- numeric comparison

elseif type(op1) == "string" and type(op2) == "string" then

return op1 <= op2 -- lexicographic comparison

else

local h = getcomphandler(op1, op2, "__le")

if h then

return h(op1, op2)

else

h = getcomphandler(op1, op2, "__lt")

if h then

return not h(op2, op1)

else

error("...");

end

end

end

end

a >= b 等价于 b <= a。

注意,在没有“le”元方法时,Lua会尝试“lt”,假定a<=b等价于not (b<a)。

"index": 索引访问table[key] function gettable_event (table, key)

local h

if type(table) == "table" then

local v = rawget(table, key)

if v ~= nil then return v end

h = metatable(table).__index

if h == nil then return nil end

else

h = metatable(table).__index

if h == nil then

error("...");

end

end

if type(h) == "function" then

return h(table, key) -- call the handler

else return h[key] -- or repeat operation on it

end

"newindex": 索引赋值table[key] = value function settable_event (table, key, value)

local h

if type(table) == "table" then

local v = rawget(table, key)

if v ~= nil then rawset(table, key, value); return end

h = metatable(table).__newindex

if h == nil then rawset(table, key, value); return end

else

h = metatable(table).__newindex

if h == nil then

error("...");

end

end

if type(h) == "function" then

return h(table, key,value) -- call the handler

else h[key] = value -- or repeat operation on it

end

"call": 当Lua调用一个值时被调用 function function_event (func, ...)

if type(func) == "function" then

return func(unpack(arg)) -- primitive call

else

local h = metatable(func).__call

if h then

return h(func, unpack(arg))

else

error("...")

end

end

end

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有