html
注:本记录都摘录自:http://manual.luaer.cn/ , lua在线手册 。1-2.5部分。程序员
相似 C 的转义符: '\a
' (响铃), '\b
' (退格), '\f
' (表单), '\n
' (换行), '\r
' (回车), '\t
' (横向制表), '\v
' (纵向制表), '\\
' (反斜杠), '\"
' (双引号), 以及 '\'
' (单引号)。 数组
反斜杠加数字的形式 \ddd
来描述一个字符,注意,若是须要在这种描述方法后接一个是数字的字符, 那么反斜杠后必须写满三个数字。闭包
下面五种方式描述了彻底相同的字符串:函数
a = 'alo\n123"' a = "alo\n123\"" a = '\97lo\10\04923"' a = [[alo 123"]] a = [==[ alo 123"]==]
Lua 中有八种基本类型: nil, boolean, number, string, function, userdata, thread, and table.lua
Boolean 类型只有两种值:false 和 true。 nil 和 false 都能致使条件为假;而另外全部的值都被看成真。spa
Number 表示实数(双精度浮点数)。操作系统
userdata 类型用来将任意 C 数据保存在 Lua 变量中。 这个类型至关于一块原生的内存,除了赋值和相同性判断,Lua 没有为之预约义任何操做。 然而,经过使用 metatable (元表) ,程序员能够为 userdata 自定义一组操做。 userdata 不能在 Lua 中建立出来,也不能在 Lua 中修改。这样的操做只能经过 C API。 这一点保证了宿主程序彻底掌管其中的数据。线程
thread 类型用来区别独立的执行线程,它被用来实现 coroutine (协同例程)。 不要把 Lua 线程跟操做系统的线程搞混。 Lua 能够在全部的系统上提供对 coroutine 的支持,即便系统并不支持线程。调试
table 类型实现了一个关联数组。语言自己采用一种语法糖,支持以 a.name
的形式表示 a["name"]。
特别的,由于函数自己也是值,因此 table 的域中也能够放函数。 这样 table 中就能够有一些 methods 了。
table, function ,thread ,和 (full) userdata 这些类型的值是所谓的对象: 变量自己并不会真正的存放它们的值,而只是放了一个对对象的引用。 赋值,参数传递,函数返回,都是对这些对象的引用进行操做; 这些操做不会作暗地里作任何性质的拷贝。
Boolean 类型只有两种值:false 和 true。 nil 和 false 都能致使条件为假;而另外全部的值都被看成真。
Number 表示实数(双精度浮点数)。
Lua 提供运行时字符串到数字的自动转换。
全局变量,局部变量,还有 table 的域。
chunk :Lua 的一个执行单元被称做 chunk。 一个 chunk 就是一串语句段,它们会被循序的执行。 每一个语句段能够以一个分号结束。lua 把一个 chunk 看成一个拥有不定参数的匿名函数 (参见 §2.5.9)处理。 正是这样,chunk 内能够定义局部变量,接收参数,而且返回值。
赋值:赋值段首先会作运算完全部的表达式,而后仅仅作赋值操做。 所以,下面这段代码
i = 3 i, a[i] = i+1, 20
会把 a[3]
设置为 20,而不会影响到 a[4]
。 这是由于 a[i]
中的 i
在被赋值为 4 以前就被拿出来了(那时是 3 )。 简单说 ,这样一行
x, y = y, x
能够用来交换 x
和 y
中的值。
for 和 while:
for v = e1, e2, e3 do block end
用while表达:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do local v = var block var = var + step end end
注意:有个问题,for i=3,2,0 do print(i) end, 会进入死循环。
可变参数:函数调用和可变参数表达式均可以放在多重返回值中。 若是表达式做为一个独立语句段出现 (这只能是一个函数调用), 它们的返回列表将被对齐到零个元素,也就是忽略全部返回值。 若是表达式用于表达式列表的最后(或者是惟一)的元素, 就不会有任何的对齐操做(除非函数调用用括号括起来)。 在任何其它的状况下,Lua 将把表达式结果当作单一元素, 忽略除第一个以外的任何值。被括号括起来的表达式永远被看成一个值。因此, (f(x,y,z))
即便 f
返回多个值,这个表达式永远是一个单一值。 ((f(x,y,z))
的值是 f
返回的第一个值。若是 f
不返回值的话,那么它的值就是 nil 。)
f() -- 调整到 0 个结果 g(f(), x) -- f() 被调整到一个结果 g(x, f()) -- g 被传入 x 加上全部 f() 的返回值 a,b,c = f(), x -- f() 被调整到一个结果 ( c 在这里被赋为 nil ) a,b = ... -- a 被赋值为可变参数中的第一个, -- b 被赋值为第二个 (若是可变参数中并无对应的值, -- 这里 a 和 b 都有可能被赋为 nil) a,b,c = x, f() -- f() 被调整为两个结果 a,b,c = f() -- f() 被调整为三个结果 return f() -- 返回 f() 返回的全部结果 return ... -- 返回全部从可变参数中接收来的值 return x,y,f() -- 返回 x, y, 以及全部 f() 的返回值 {f()} -- 用 f() 的全部返回值建立一个列表 {...} -- 用可变参数中的全部值建立一个列表 {f(), nil} -- f() 被调整为一个结果
比较操做符:等于操做 (==
) 首先比较操做数的类型。 若是类型不一样,结果就是 false。 不然,继续比较值。 数字和字符串都用常规的方式比较。 对象 (table ,userdata ,thread ,以及函数)以引用的形式比较: 两个对象只有在它们指向同一个东西时才认为相等。 每次你建立一个新对象(一个 table 或是 userdata ,thread 函数), 它们都各不相同,即不一样于上次建立的东西。
and, or, 以及 not:and要找一个假的,or要找一个真的,找到就返回;到最后也找不到就返回最后的元素。
10 or 20 --> 10 10 or error() --> 10 nil or "a" --> "a" nil and 10 --> nil false and error() --> false false and nil --> false false or nil --> nil 10 and 20 --> 20
操做符的优先级:写在下表中,从低到高优先级排序:
or and < > <= >= ~= == .. + - * / % not # - (unary) ^
一般,能够用括号来改变运算次序。 链接操做符 ('..
') 和幂操做 ('^
') 是从右至左的。 其它全部的操做都是从左至右。下面是一些例子:
print(false or 5 and 6) --> 6 print(false or 5 and nil) --> nil print(false or 2+3 >= 4*1 and not 7^2) --> false print(false or 2+3 >= 4*1 and not nil) --> true print(not nil) --> true print(false or nil) --> nil
经常使用却不在乎的元方法:
"lt" 或是 "le":大小比较操做以如下方式进行。 若是参数都是数字,那么就直接作数字比较。 不然,若是参数都是字符串,就用字符串比较的方式进行。 再则,Lua 就试着调用 "lt" 或是 "le" 元方法 。
concat:字符串的链接操做符写做两个点 ('..
')。 若是两个操做数都是字符串或都是数字,链接操做将以 §2.2.1 中提到的规则把其转换为字符串。 不然,会取调用元方法 "concat"。
取长度操做符:写做一元操做 #
。 字符串的长度是它的字节数(就是以一个字符一个字节计算的字符串长度)。
table t
的长度被定义成一个整数下标 n
。 它知足 t[n]
不是 nil 而 t[n+1]
为 nil; 此外,若是 t[1]
为 nil ,n
就多是零。 对于常规的数组,里面从 1 到 n
放着一些非空的值的时候, 它的长度就精确的为 n
,即最后一个值的下标。 若是数组有一个“空洞” (就是说,nil 值被夹在非空值之间), 那么 #t
多是任何一个是 nil 值的位置的下标 (就是说,任何一个 nil 值都有可能被当成数组的结束)。
语法糖:
表:a.name
的形式表示 a["name"];
函数: v:name(args)
这个样子,被解释成 v.name(v,args)
, 这里 v
只会被求值一次。
函数:调用形式 f{fields}
是一种语法糖用于表示 f({fields})
; 这里指参数列表是一个单一的新建立出来的列表;
函数:形式 f'string'
(或是 f"string"
亦或是 f[[string]]
) 也是一种语法糖,用于表示 f('string')
; 这里指参数列表是一个单独的字符串。
冒号语法能够用来定义方法, 就是说,函数能够有一个隐式的形参 self。 所以,以下写法:
function t.a.b.c:f (params) body end
是这样一种写法的语法糖:
t.a.b.c.f = function (self, params) body end
简化函数定义:
这样的写法:
function f () body end
被转换成
f = function () body end
这样的写法:
function t.a.b.c.f () body end
被转换成
t.a.b.c.f = function () body end
这样的写法:
local function f () body end
被转换成
local f; f = function () body end
注意,并非转换成
local f = function () body end
(这个差异只在函数体内须要引用 f 时才有。)
尾调用:调用形式:return
functioncall 将触发一个尾调用。 Lua 实现了适当的尾部调用(或是适当的尾递归): 在尾调用中, 被调用的函数重用调用它的函数的堆栈项。 所以,对于程序执行的嵌套尾调用的层数是没有限制的。 然而,尾调用将删除调用它的函数的任何调试信息。 注意,尾调用只发生在特定的语法下, 这时, return 只有单一函数调用做为参数; 这种语法使得调用函数的结果能够精确返回。 所以,下面这些例子都不是尾调用:
return (f(x)) -- 返回值被调整为一个 return 2 * f(x) return x, f(x) -- 最加若干返回值 f(x); return -- 无返回值 return x or f(x) -- 返回值被调整为一个
闭包:一个函数定义是一个可执行的表达式, 执行结果是一个类型为 function 的值。 当 Lua 预编译一个 chunk 的时候, chunk 做为一个函数,整个函数体也就被预编译了。 那么,不管什么时候 Lua 执行了函数定义, 这个函数自己就被实例化了(或者说是关闭了)。 这个函数的实例(或者说是closure(闭包)) 是表达式的最终值。 相同函数的不一样实例有可能引用不一样的外部局部变量, 也可能拥有不一样的环境表。
形参,实参:当一个函数被调用, 若是函数没有被定义为接收不定长参数,即在形参列表的末尾注明三个点 ('...
'), 那么实参列表就会被调整到形参列表的长度, 变长参数函数不会调整实参列表; 取而代之的是,它将把全部额外的参数放在一块儿经过变长参数表达式传递给函数, 其写法依旧是三个点。 这个表达式的值是一串实参值的列表,看起来就跟一个能够返回多个结果的函数同样。 若是一个变长参数表达式放在另外一个表达式中使用,或是放在另外一串表达式的中间, 那么它的返回值就会被调整为单个值。 若这个表达式放在了一系列表达式的最后一个,就不会作调整了(除非用括号给括了起来)。
咱们先作以下定义,而后再来看一个例子:
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, ... --> (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
地方