⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lua 5_1 参考手册.htm

📁 Lua 是一个扩展式程序设计语言
💻 HTM
📖 第 1 页 / 共 5 页
字号:
     return ...         -- 返回所有从可变参数中接收来的值
     return x,y,f()     -- 返回 x, y, 以及所有 f() 的返回值
     {f()}              -- 用 f() 的所有返回值创建一个列表
     {...}              -- 用可变参数中的所有值创建一个列表
     {f(), nil}         -- f() 被调整为一个结果
</PRE>
<P>被括号括起来的表达式永远被当作一个值。所以, <CODE>(f(x,y,z))</CODE> 即使 <CODE>f</CODE> 
返回多个值,这个表达式永远是一个单一值。(<CODE>(f(x,y,z))</CODE> 的值是 <CODE>f</CODE> 返回的第一个值。如果 
<CODE>f</CODE> 不返回值的话,那么它的值就是 <B>nil</B> 。) 
<H3>2.5.1 - <A name=2.5.1>数学运算操作符</A></H3>
<P>Lua 支持常见的数学运算操作符:二元操作 <CODE>+</CODE> (加法), <CODE>-</CODE> (减法),<CODE>*</CODE> 
(乘法), <CODE>/</CODE> (除法), <CODE>%</CODE> (取模),以及 <CODE>^</CODE> (幂);和一元操作 
<CODE>-</CODE> (取负)。如果对数字操作,或是可以转换为数字的字符串(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.2.1">§2.2.1</A>),所有这些操作都依赖它通常的含义。幂操作可以对任何幂值都正常工作。比如, 
<CODE>x^(-0.5)</CODE> 将计算出 <CODE>x</CODE> 的平方根。取模操作被定义为 <PRE>     a % b == a - math.floor(a/b)*b
</PRE>
<P>这就是说,其结果是商相对负无穷圆整后的余数。(译注:负数对正数取模的结果为正数) 
<H3>2.5.2 - <A name=2.5.2>比较操作符</A></H3>
<P>Lua 中的比较操作符有 <PRE>     ==    ~=    &lt;     &gt;     &lt;=    &gt;=
</PRE>
<P>这些操作的结果不是 <B>false</B> 就是 <B>true</B>。 
<P>等于操作 (<CODE>==</CODE>) 首先比较操作数的类型。如果类型不同,结果就是 
<B>false</B>。否则,继续比较值。数字和字符串都用常规的方式比较。对象 (table ,userdata ,thread 
,以及函数)以引用的形式比较:两个对象只有在它们指向同一个东西时才认为相等。每次你创建一个新对象(一个 table 或是 userdata ,thread 
函数),它们都各不相同,即不同于上次创建的东西。 
<P>你可以改变 Lua 比较 table 和 userdata 的方式,这需要使用 "eq" 这个原方法(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.8">§2.8</A>)。 
<P><A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.2.1">§2.2.1</A> 
中提及的转换规则并不作用于比较操作。所以, <CODE>"0"==0</CODE> 等于 <B>false</B>,而且 <CODE>t[0]</CODE> 和 
<CODE>t["0"]</CODE> 描述的是 table 中不同的域。 
<P>操作符 <CODE>~=</CODE> 完全等价于 (<CODE>==</CODE>) 操作的反值。 
<P>大小比较操作以以下方式进行。如果参数都是数字,那么就直接做数字比较。否则,如果参数都是字符串,就用字符串比较的方式进行。再则,Lua 就试着调用 "lt" 
或是 "le" 元方法(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.8">§2.8</A>)。 
<H3>2.5.3 - <A name=2.5.3>逻辑操作符</A></H3>
<P>Lua 中的逻辑操作符有 <B>and</B>, <B>or</B>, 以及 <B>not</B>。和控制结构(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.4.4">§2.4.4</A>)一样,所有的逻辑操作符把 
<B>false</B> 和 <B>nil</B> 都作为假,而其它的一切都当作真。 
<P>取反操作 <B>not</B> 总是返回 <B>false</B> 或 <B>true</B> 中的一个。与操作符 <B>and</B> 在第一个参数为 
<B>false</B> 或 <B>nil</B> 时返回这第一个参数;否则,<B>and</B> 返回第二个参数。或操作符 <B>or</B> 
在第一个参数不为 <B>nil</B> 也不为 <B>false</B> 时,返回这第一个参数,否则返回第二个参数。 <B>and</B> 和 
<B>or</B> 都遵循短路规则;也就是说,第二个操作数只在需要的时候去求值。这里有一些例子: <PRE>     10 or 20            --&gt; 10
     10 or error()       --&gt; 10
     nil or "a"          --&gt; "a"
     nil and 10          --&gt; nil
     false and error()   --&gt; false
     false and nil       --&gt; false
     false or nil        --&gt; nil
     10 and 20           --&gt; 20
</PRE>
<P>(在这本手册中, --&gt; 指前面表达式的结果。) 
<H3>2.5.4 - <A name=2.5.4>连接符</A></H3>
<P>Lua 中字符串的连接操作符写作两个点 ('<CODE>..</CODE>')。如果两个操作数都是字符串或都是数字,连接操作将以 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.2.1">§2.2.1</A> 
中提到的规则把其转换为字符串。否则,会取调用元方法 "concat" (参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.8">§2.8</A>)。 
<H3>2.5.5 - <A name=2.5.5>取长度操作符</A></H3>
<P>取长度操作符写作一元操作 <CODE>#</CODE>。字符串的长度是它的字节数(就是以一个字符一个字节计算的字符串长度)。 
<P>table <CODE>t</CODE> 的长度被定义成一个整数下标 <CODE>n</CODE> 。它满足 <CODE>t[n]</CODE> 不是 
<B>nil</B> 而 <CODE>t[n+1]</CODE> 为 <B>nil</B>;此外,如果 <CODE>t[1]</CODE> 为 
<B>nil</B> ,<CODE>n</CODE> 就可能是零。对于常规的数组,里面从 1 到 <CODE>n</CODE> 
放着一些非空的值的时候,它的长度就精确的为 <CODE>n</CODE>,即最后一个值的下标。如果数组有一个“空洞” (就是说,<B>nil</B> 
值被夹在非空值之间),那么 <CODE>#t</CODE> 可能是任何一个是 <B>nil</B> 值的位置的下标(就是说,任何一个 <B>nil</B> 
值都有可能被当成数组的结束)。 
<H3>2.5.6 - <A name=2.5.6>优先级</A></H3>
<P>Lua 中操作符的优先级写在下表中,从低到高优先级排序: <PRE>     or
     and
     &lt;     &gt;     &lt;=    &gt;=    ~=    ==
     ..
     +     -
     *     /     %
     not   #     - (unary)
     ^
</PRE>
<P>通常,你可以用括号来改变运算次序。连接操作符 ('<CODE>..</CODE>') 和幂操作 ('<CODE>^</CODE>') 
是从右至左的。其它所有的操作都是从左至右。 
<H3>2.5.7 - <A name=2.5.7>Table 构造</A></H3>
<P>table 构造子是一个构造 table 的表达式。每次构造子被执行,都会构造出一个新的 table 。构造子可以被用来构造一个空的 
table,也可以用来构造一个 table 并初始化其中的一些域。一般的构造子的语法如下 <PRE>	tableconstructor ::= `<B>{</B>&acute; [fieldlist] `<B>}</B>&acute;
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= `<B>[</B>&acute; exp `<B>]</B>&acute; `<B>=</B>&acute; exp | Name `<B>=</B>&acute; exp | exp
	fieldsep ::= `<B>,</B>&acute; | `<B>;</B>&acute;
</PRE>
<P>每个形如 <CODE>[exp1] = exp2</CODE> 的域向 table 中增加新的一项,其键值为 <CODE>exp1</CODE> 而值为 
<CODE>exp2</CODE>。形如 <CODE>name = exp</CODE> 的域等价于 <CODE>["name"] = 
exp</CODE>。最后,形如 <CODE>exp</CODE> 的域等价于 <CODE>[i] = exp</CODE> , 这里的 
<CODE>i</CODE> 是一个从 1 开始不断增长的数字。这这个格式中的其它域不会破坏其记数。举个例子: <PRE>     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
</PRE>
<P>等价于 <PRE>     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end
</PRE>
<P>如果表单中最后一个域的形式是 <CODE>exp</CODE> 
,而且其表达式是一个函数调用或者是一个可变参数,那么这个表达式所有的返回值将连续的进入列表(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.5.8">§2.5.8</A>)。为了避免这一点,你可以用括号把函数调用(或是可变参数)括起来(参见 
<A href="http://www.codingnow.com/2000/download/lua_manual.html#2.5">§2.5</A>)。 
<P>初始化域表可以在最后多一个分割符,这样设计可以方便由机器生成代码。 
<H3>2.5.8 - <A name=2.5.8>函数调用</A></H3>
<P>Lua 中的函数调用的语法如下: <PRE>	functioncall ::= prefixexp args
</PRE>
<P>函数调用时,第一步,prefixexp 和 args 先被求值。如果 prefixexp 的值的类型是 
<EM>function</EM>,那么这个函数就被用给出的参数调用。否则 prefixexp 的元方法 "call" 就被调用,第一个参数就是 
prefixexp 的值,跟下来的是原来的调用参数(参见 <A 
href="http://www.codingnow.com/2000/download/lua_manual.html#2.8">§2.8</A>)。 
<P>这样的形式 <PRE>	functioncall ::= prefixexp `<B>:</B>&acute; Name args
</PRE>
<P>可以用来调用 "方法"。这是 Lua 支持的一种语法糖。像 <CODE>v:name(<EM>args</EM>)</CODE> 这个样子,被解释成 
<CODE>v.name(v,<EM>args</EM>)</CODE>,这里 <CODE>v</CODE> 只会被求值一次。 
<P>参数的语法如下: <PRE>	args ::= `<B>(</B>&acute; [explist1] `<B>)</B>&acute;
	args ::= tableconstructor
	args ::= String
</PRE>
<P>所有参数的表达式求值都在函数调用之前。这样的调用形式 <CODE>f{<EM>fields</EM>}</CODE> 是一种语法糖用于表示 
<CODE>f({<EM>fields</EM>})</CODE>;这里指参数列表是一个单一的新创建出来的列表。而这样的形式 
<CODE>f'<EM>string</EM>'</CODE> (或是 <CODE>f"<EM>string</EM>"</CODE> 亦或是 
<CODE>f[[<EM>string</EM>]]</CODE>)也是一种语法糖,用于表示 
<CODE>f('<EM>string</EM>')</CODE>;这里指参数列表是一个单独的字符串。 
<P>因为表达式语法在 Lua 中比较自由,所以你不能在函数调用的 '<CODE>(</CODE>' 前换行。这个限制可以避免语言中的一些歧义。比如你这样写 <PRE>     a = f
     (g).x(a)
</PRE>
<P>Lua 将把它当作一个单一语句段, <CODE>a = f(g).x(a)</CODE> 
。因此,如果你真的想作为成两个语句段,你必须在它们之间写上一个分号。如果你真的想调用 <CODE>f</CODE>,你必须从 <CODE>(g)</CODE> 
前移去换行。 
<P>这样一种调用形式:<CODE>return</CODE> <EM>functioncall</EM> 将触发一个尾调用。 Lua 
实现了适当的尾部调用(或是适当的尾递归):在尾调用中,被调用的函数重用调用它的函数的堆栈项。因此,对于程序执行的嵌套尾调用的层数是没有限制的。然而,尾调用将删除调用它的函数的任何调试信息。注意,尾调用只发生在特定的语法下,这时, 
<B>return</B> 只有单一函数调用作为参数;这种语法使得调用函数的结果可以精确返回。因此,下面这些例子都不是尾调用: <PRE>     return (f(x))        -- 返回值被调整为一个
     return 2 * f(x)
     return x, f(x)       -- 最加若干返回值
     f(x); return         -- 无返回值
     return x or f(x)     -- 返回值被调整为一个
</PRE>
<H3>2.5.9 - <A name=2.5.9>函数定义</A></H3>
<P>函数定义的语法如下: <PRE>	function ::= <B>function</B> funcbody
	funcbody ::= `<B>(</B>&acute; [parlist1] `<B>)</B>&acute; block <B>end</B>
</PRE>
<P>另外定义了一些语法糖简化函数定义的写法: <PRE>	stat ::= <B>function</B> funcname funcbody
	stat ::= <B>local</B> <B>function</B> Name funcbody
	funcname ::= Name {`<B>.</B>&acute; Name} [`<B>:</B>&acute; Name]
</PRE>
<P>这样的写法: <PRE>     function f () <EM>body</EM> end
</PRE>
<P>被转换成 <PRE>     f = function () <EM>body</EM> end
</PRE>
<P>这样的写法: <PRE>     function t.a.b.c.f () <EM>body</EM> end
</PRE>
<P>被转换成 <PRE>     t.a.b.c.f = function () <EM>body</EM> end
</PRE>
<P>这样的写法: <PRE>     local function f () <EM>body</EM> end
</PRE>
<P>被转换成 <PRE>     local f; f = function () <EM>body</EM> end
</PRE>
<P>注意,并不是转换成 <PRE>     local f = function () <EM>body</EM> end
</PRE>
<P>(这个差别只在函数体内需要引用 <CODE>f</CODE> 时才有。) 
<P>一个函数定义是一个可执行的表达式,执行结果是一个类型为 <EM>function</EM> 的值。当 Lua 预编译一个 chunk 的时候, chunk 
作为一个函数,整个函数体也就被预编译了。那么,无论何时 Lua 执行了函数定义,这个函数本身就被实例化了(或者说是关闭了)。这个函数的实例(或者说是 
<EM>closure</EM>(闭包))是表达式的最终值。相同函数的不同实例有可能引用不同的外部局部变量,也可能拥有不同的环境表。 
<P>形参(函数定义需要的参数)是一些由实参(实际传入参数)的值初始化的局部变量: <PRE>	parlist1 ::= namelist [`<B>,</B>&acute; `<B>...</B>&acute;] | `<B>...</B>&acute;
</PRE>
<P>当一个函数被调用,如果函数没有被定义为接收不定长参数,即在形参列表的末尾注明三个点 
('<CODE>...</CODE>'),那么实参列表就会被调整到形参列表的长度,变长参数函数不会调整实参列表;取而代之的是,它将把所有额外的参数放在一起通过变长参数表达式传递给函数,其写法依旧是三个点。这个表达式的值是一串实参值的列表,看起来就跟一个可以返回多个结果的函数一样。如果一个变长参数表达式放在另一个表达式中使用,或是放在另一串表达式的中间,那么它的返回值就会被调整为单个值。若这个表达式放在了一系列表达式的最后一个,就不会做调整了(除非用括号给括了起来)。 

<P>我们先做如下定义,然后再来看一个例子: <PRE>     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end
</PRE>
<P>下面看看实参到形参数以及可变长参数的映射关系: <PRE>     CALL            PARAMETERS
     

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -