语言特点
- 动态数据类型
- 唯一一种数据结构 —— 表
- 函数是一等类型,支持匿名函数和正则尾递归
- 支持词法定界和闭包
- 提供 thread 类型和结构化的协程机制
- 运行期能编译字符串形式的程序文本并载入虚拟机执行
参考: https://www.gitbook.com/book/moonbingbing/openresty-best-practices/details
LuaJIT
LuaJIT 是采用 C 和汇编语言编写的 Lua 解释器与即时编译器。LuaJIT 被设计成全兼容标准的 Lua 5.1 语言,同时可选地支持 Lua 5.2 和 Lua 5.3 中的一些不破坏向后兼容性的有用特性。因此,标准 Lua 语言的代码可以不加修改地运行在 LuaJIT 之上。可以说 LuaJIT 是一个高效的 Lua 实现。
利用即时编译(Just-in Time )技术把 Lua 代码编译成本地机器码后交由 CPU 直接执行。在数值运算、循环与函数调用、协程切换、字符串操作等许多方面它的加速效果都很显著。
数据类型
类型 | 示例 |
---|---|
nil | nil |
boolean | true,false |
number | 3.99 |
string | “hello world” |
table | {web = “www.google.com”} |
字符串还可以用一种长括号(即 [[]],[=[]=],[==[]==],[===[]===],[====[]====])。这种方式描述的字符串可以包含任何东西,当然本级别的反长括号除外。例:[[abc\nbc]] ,里面的 “\n” 不会被转义。
Lua 字符串一般都会经历一个 “ 内化 ”(intern )的过程,即两个完全一样的 Lua 字符串在 Lua 虚拟机中只会存储一份。每一个 Lua 字符串在创建时都会插入到 Lua 虚拟机内部的一个全局的哈希表中。
运算符
算术运算符 | 说明 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
^ | 指数 |
% | 取模 |
关系运算符 | 说明 |
---|---|
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
== | 等于 |
~= | 不等于 |
逻辑运算符 | 说明 |
---|---|
and | 逻辑与 |
or | 逻辑或 |
not | 逻辑非 |
特殊操作符
#
取长度操作符
print(#"hello world") -- 输出 11 |
对于常规的数组,里面从 1 到 n 放着一些非空的值的时候,它的长度就精确的为 n,即最后一个值的下标。如果数组有一个 “ 空洞 ”(就是说,nil 值被夹在非空值之间),那么 #t 可能是指向任何一个是 nil 值的前一个位置的下标(就是说,任何一个 nil 值都有可能被当成数组的结束)。这也就说明对于有 “ 空洞 ” 的情况,table 的长度存在一定的 不可确定性。
..
字符串连接符
print("Hello " .. "World") |
所有逻辑操作符将 false 和 nil 视作假,其他任何值视作真,对于 and 和 or,“ 短路求值 ”,对于 not,永远只返回 true 或者 false。
字符串连接
在 Lua 中连接两个字符串,可以使用操作符 “..”(两个点)。如果其任意一个操作数是数字的话,Lua 会将这个数字转换成字符串。注意,连接操作符只会创建一个新字符串,而不会改变原操作数。也可以使用 string 库函数 string.format 连接字符串。
print("Hello " .. "World") -->打印 Hello World |
控制结构
选择判断
- if then end
- if then else end
- if then elseif then else end
if score == 100 then |
循环
while do end
while x <= 5 do |
repeat until
repeat |
for do
for var = begin, finish, step do |
for in do
for i, v in ipairs(a) do |
ipairs() 内建函数是可以被 JIT 编译的,而 pairs() 则只能被解释执行。因此在性能敏感的场景,应当合理安排数据结构,避免对哈希表进行遍历。事实上,即使未来 pairs 可以被 JIT 编译,哈希表的遍历本身也不会有数组遍历那么高效,毕竟哈希表就不是为遍历而设计的数据结构。
没有 continue 只有 break
变量
Lua 中的局部变量要用 local 关键字来显式定义
不使用 local 显式定义的变量就是全局变量
g_var = 1 -- global var |
作用域
局部变量的生命周期是有限的,它的作用域仅限于声明它的块(block )。
一个块是一个控制结构的执行体、或者是一个函数的执行体再或者是一个程序块(chunk )。
函数
Lua 使用关键字 function 定义函数
-- 全局方法 |
函数定义等价于变量赋值 , 也可以把函数名替换为某个 Lua 表的某个字段
function foo.bar(a, b, c) |
变长参数
local function func( ... ) -- 形参为 ... ,表示函数采用变长参数 |
具名参数 及 引用传递
当函数参数是 table 类型时,传递进来的是 实际参数的引用,此时在函数内部对该 table 所做的修改,会直接对调用者所传递的实际参数生效
function change(arg) --change函数,改变长方形的长和宽,使其各增长一倍 |
函数返回多值
local function swap(a, b) -- 定义函数 swap,实现两个变量交换值 |
调整规则: 若返回值个数大于接收变量的个数,多余的返回值会被忽略掉; 若返回值个数小于参数个数,从左向右,没有被返回值初始化的变量会被初始化为 nil。
当一个函数有一个以上返回值,且函数调用不是一个列表表达式的最后一个元素,那么函数调用只会产生一个返回值 , 也就是第一个返回值。
local function init() -- init 函数 返回两个值 1 和 "lua" |
确保只取函数返回值的第一个值,可以使用括号运算符
local function init() |
值得一提的是,如果实参列表中某个函数会返回多个值,同时调用者又没有显式地使用括号运算符来筛选和过滤,则这样的表达式是不能被 LuaJIT 2 所 JIT 编译的,而只能被解释执行。
函数动态调用
unpack
local args = {...} or {} |
unpack 内建函数还不能为 LuaJIT 所 JIT 编译,因此这种用法总是会被解释执行。对性能敏感的代码路径应避免这种用法。
注释
- 单行注释
--
功能等同于 C++ 中的 // - 多行注释
--[[ 注释的内容 ]]
功能等同于 C++ 中的 /**/ - 多行注释
--[====[ 注释和内容 ]====]
, 也等同于 C++ 中的 /**/, 这个主要用于注释的内容里面有像 arr[arr2[idx]] 这种文本 , 如果使用 –[[ ]] 遇到 arr[arr2[idx]] 后面的 ]] 注释就结束 , 这显示与我们的意图不相符合 . 所以使用 –[===[ ]===] 来注释内容 , 就不用担心了 , 两边的等号数量要相同 , 多少个没有关系
模块
Lua 提供了一个名为 require
的函数用来加载模块。模块加载后的结果通过是一个 Lua table,这个表就像是一个命名空间,其内容就是模块中导出的所有东西,比如函数和变量。
要加载一个模块,只需要简单地调用 require ("file")
就可以了,file 指模块所在的文件名。
local fp = require("my") |
对于需要导出给外部使用的公共模块,处于安全考虑,是要避免全局变量的出现。
Table
在 Lua 中,数组下标从 1 开始计数。
在初始化一个数组的时候,若不显式地用键值对方式赋值,则会默认用数字作为下标,从 1 开始。由于在 Lua 内部实际采用哈希表和数组分别保存键值对、普通值,所以不推荐混合使用这两种赋值方式。
追加到 table 的末尾用的是 s[#s+1] = something
不要在 Lua 的 table 中使用 nil 值,如果一个元素要删除,直接 remove,不要用 nil 去代替。
所有索引值都需要用 “[]” 括起来;如果是字符串,还可以去掉引号和中括号; 即如果没有 [] 括起,则认为是字符串索引
s={a=1,b=2} |
- 获取长度:
table.getn(table)
s={1,2,3} |
- table 连接成字符串:
table.concat( tablename, sep, start_index, end_index )
local a = {1, 3, 5, "hello" } |
- 插入值:
table.insert (table, [pos 位置 ,] value)
local a = {1, 8} --a[1] = 1,a[2] = 8 |
- 最大索引编号:
table.maxn (table)
返回(数组型)表 table 的最大索引编号;如果此表没有正的索引编号,返回 0。
- 删除值:
table.remove (table [, pos])
在表 table 中删除索引为 pos(pos 只能是 number 型)的元素,并返回这个被删除的元素,它后面所有元素的索引值都会减一。pos 的默认值是表的长度,即默认是删除表的最后一个元素。
local a = { 1, 2, 3, 4} |
- 表排序:
table.sort (table [, comp])
按照给定的比较函数 comp 给表 table 排序,也就是从 table[1] 到 table[n],这里 n 表示 table 的长度。 比较函数有两个参数,如果希望第一个参数排在第二个的前面,就应该返回 true,否则返回 false。 如果比较函数 comp 没有给出,默认从小到大排序。
local function compare(x, y) --从大到小排序 |