📄 lua 5_1 参考手册.htm
字号:
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, ... --> (nothing)
g(3, 4) a=3, b=4, ... --> (nothing)
g(3, 4, 5, 8) a=3, b=4, ... --> 5 8
g(5, r()) a=5, b=1, ... --> 2 3
</PRE>
<P>结果由 <B>return</B> 来返回(参见 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#2.4.4">§2.4.4</A>)。如果执行到函数末尾依旧没有遇到任何
<B>return</B> 语句,函数就不会返回任何结果。
<P>冒号语法可以用来定义方法,就是说,函数可以有一个隐式的形参 <CODE>self</CODE>。因此,如下写法: <PRE> function t.a.b.c:f (<EM>params</EM>) <EM>body</EM> end
</PRE>
<P>是这样一种写法的语法糖: <PRE> t.a.b.c.f = function (self, <EM>params</EM>) <EM>body</EM> end
</PRE>
<H2>2.6 - <A name=2.6>可视规则</A></H2>
<P>Lua 是一个有词法作用范围的语言。变量的作用范围开始于声明它们之后的第一个语句段,结束于包含这个声明的最内层语句块的结束点。看下面这些例子: <PRE> x = 10 -- 全局变量
do -- 新的语句块
local x = x -- 新的一个 'x', 它的值现在是 10
print(x) --> 10
x = x+1
do -- 另一个语句块
local x = x+1 -- 又一个 'x'
print(x) --> 12
end
print(x) --> 11
end
print(x) --> 10 (取到的是全局的那一个)
</PRE>
<P>注意这里,类似 <CODE>local x = x</CODE> 这样的声明,新的 <CODE>x</CODE>
正在被声明,但是还没有进入它的作用范围,所以第二个 <CODE>x</CODE> 指向的是外面一层的变量。
<P>因为有这样一个词法作用范围的规则,所以可以在函数内部自由的定义局部变量并使用它们。当一个局部变量被更内层的函数中使用的时候,它被内层函数称作
<EM>upvalue</EM>(上值),或是 <EM>外部局部变量</EM>。
<P>注意,每次执行到一个 local 语句都会定义出一个新的局部变量。看看这样一个例子: <PRE> a = {}
local x = 20
for i=1,10 do
local y = 0
a[i] = function () y=y+1; return x+y end
end
</PRE>
<P>这个循环创建了十个 closure(这指十个匿名函数的实例)。这些 closure 中的每一个都使用了不同的 <CODE>y</CODE>
变量,而它们又共享了同一份 <CODE>x</CODE>。
<H2>2.7 - <A name=2.7>错误处理</A></H2>
<P>因为 Lua 是一个嵌入式的扩展语言,所有的 Lua 动作都是从宿主程序的 C 代码调用 Lua 库(参见 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#lua_pcall"><CODE>lua_pcall</CODE></A>)中的一个函数开始的。在
Lua 编译或运行的任何时候发生了错误,控制权都会交还给 C ,而 C 可以来做一些恰当的措施(比如打印出一条错误信息)。
<P>Lua 代码可以显式的调用 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-error"><CODE>error</CODE></A>
函数来产生一条错误。如果你需要在 Lua 中捕获发生的错误,你可以使用 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-pcall"><CODE>pcall</CODE></A>
函数。
<H2>2.8 - <A name=2.8>Metatable(元表)</A></H2>
<P>Lua 中的每个值都可以用一个 <EM>metatable</EM>。这个 <EM>metatable</EM> 就是一个原始的 Lua table
,它用来定义原始值在特定操作下的行为。你可以通过在 metatable 中的特定域设一些值来改变拥有这个 metatable
的值的指定操作之行为。举例来说,当一个非数字的值作加法操作的时候, Lua 会检查它的 metatable 中 <CODE>"__add"</CODE>
域中的是否有一个函数。如果有这么一个函数的话,Lua 调用这个函数来执行一次加法。
<P>我们叫 metatable 中的键名为 <EM>事件 (event)</EM> ,把其中的值叫作 <EM>元方法
(metamethod)</EM>。在上个例子中,事件是 <CODE>"add"</CODE> 而元方法就是那个执行加法操作的函数。
<P>你可以通过 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-getmetatable"><CODE>getmetatable</CODE></A>
函数来查询到任何一个值的 metatable。
<P>你可以通过 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-setmetatable"><CODE>setmetatable</CODE></A>
函数来替换掉 table 的 metatable 。你不能从 Lua 中改变其它任何类型的值的 metatable (使用 debug
库例外);要这样做的话必须使用 C API 。
<P>每个 table 和 userdata 拥有独立的 metatable (当然多个 table 和 userdata 可以共享一个相同的表作它们的
metatable);其它所有类型的值,每种类型都分别共享唯一的一个 metatable。因此,所有的数字一起只有一个 metatable
,所有的字符串也是,等等。
<P>一个 metatable 可以控制一个对象做数学运算操作、比较操作、连接操作、取长度操作、取下标操作时的行为, metatable
中还可以定义一个函数,让 userdata 作垃圾收集时调用它。对于这些操作,Lua 都将其关联上一个被称作事件的指定健。当 Lua
需要对一个值发起这些操作中的一个时,它会去检查值中 metatable 中是否有对应事件。如果有的话,键名对应的值(元方法)将控制 Lua 怎样做这个操作。
<P>metatable 可以控制的操作已在下面列出来。每个操作都用相应的名字区分。每个操作的键名都是用操作名字加上两个下划线
'<CODE>__</CODE>' 前缀的字符串;举例来说,"add" 操作的键名就是字符串 <CODE>"__add"</CODE>。这些操作的语义用一个
Lua 函数来描述解释器如何执行更为恰当。
<P>这里展示的用 Lua 写的代码仅作解说用;实际的行为已经硬编码在解释器中,其执行效率要远高于这些模拟代码。这些用于描述的的代码中用到的函数( <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-rawget"><CODE>rawget</CODE></A>
, <A
href="http://www.codingnow.com/2000/download/lua_manual.html#pdf-tonumber"><CODE>tonumber</CODE></A>
,等等。)都可以在 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#5.1">§5.1</A>
中找到。特别注意,我们使用这样一个表达式来从给定对象中提取元方法 <PRE> metatable(obj)[event]
</PRE>
<P>这个应该被解读作 <PRE> rawget(getmetatable(obj) or {}, event)
</PRE>
<P>这就是说,访问一个元方法不再会触发任何的元方法,而且访问一个没有 metatable 的对象也不会失败(而只是简单返回 <B>nil</B>)。
<UL>
<LI><B>"add":</B> <CODE>+</CODE> 操作。
<P>下面这个 <CODE>getbinhandler</CODE> 函数定义了 Lua 怎样选择一个处理器来作二元操作。首先,Lua
尝试第一个操作数。如果这个东西的类型没有定义这个操作的处理器,然后 Lua 会尝试第二个操作数。 <PRE> function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]
end
</PRE>
<P>通过这个函数, <CODE>op1 + op2</CODE> 的行为就是 <PRE> function add_event (op1, op2)
local o1, o2 = tonumber(op1), tonumber(op2)
if o1 and o2 then -- 两个操作数都是数字?
return o1 + o2 -- 这里的 '+' 是原生的 'add'
else -- 至少一个操作数不是数字时
local h = getbinhandler(op1, op2, "__add")
if h then
-- 以两个操作数来调用处理器
return h(op1, op2)
else -- 没有处理器:缺省行为
error(···)
end
end
end
</PRE>
<P></P>
<LI><B>"sub":</B> <CODE>-</CODE> 操作。 其行为类似于 "add" 操作。
<LI><B>"mul":</B> <CODE>*</CODE> 操作。 其行为类似于 "add" 操作。
<LI><B>"div":</B> <CODE>/</CODE> 操作。 其行为类似于 "add" 操作。
<LI><B>"mod":</B> <CODE>%</CODE> 操作。 其行为类似于 "add" 操作,它的原生操作是这样的 <CODE>o1 -
floor(o1/o2)*o2</CODE>
<LI><B>"pow":</B> <CODE>^</CODE> (幂)操作。 其行为类似于 "add" 操作,它的原生操作是调用
<CODE>pow</CODE> 函数(通过 C math 库)。
<LI><B>"unm":</B> 一元 <CODE>-</CODE> 操作。 <PRE> function unm_event (op)
local o = tonumber(op)
if o then -- 操作数是数字?
return -o -- 这里的 '-' 是一个原生的 'unm'
else -- 操作数不是数字。
-- 尝试从操作数中得到处理器
local h = metatable(op).__unm
if h then
-- 以操作数为参数调用处理器
return h(op)
else -- 没有处理器:缺省行为
error(···)
end
end
end
</PRE>
<P></P>
<LI><B>"concat":</B> <CODE>..</CODE> (连接)操作, <PRE> 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 -- 原生字符串连接
else
local h = getbinhandler(op1, op2, "__concat")
if h then
return h(op1, op2)
else
error(···)
end
end
end
</PRE>
<P></P>
<LI><B>"len":</B> <CODE>#</CODE> 操作。 <PRE> function len_event (op)
if type(op) == "string" then
return strlen(op) -- 原生的取字符串长度
elseif type(op) == "table" then
return #op -- 原生的取 table 长度
else
local h = metatable(op).__len
if h then
-- 调用操作数的处理器
return h(op)
else -- 没有处理器:缺省行为
error(···)
end
end
end
</PRE>
<P>关于 table 的长度参见 <A
href="http://www.codingnow.com/2000/download/lua_manual.html#2.5.5">§2.5.5</A>
。 </P>
<LI><B>"eq":</B> <CODE>==</CODE> 操作。 函数 <CODE>getcomphandler</CODE> 定义了 Lua
怎样选择一个处理器来作比较操作。元方法仅仅在参于比较的两个对象类型相同且有对应操作相同的元方法时才起效。 <PRE> 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
</PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -