这一篇记录一些关于Lua的更深入一些的东西主要是table的使用。但是不涉及IO,Debug,垃圾回收,OOP,数据库访问。这些东西我觉得可以单独放在一个专题写。

lua调用其他平台库这里不做介绍

调用C库

包概念

环境配置

.bash_profile 文件中直接配置测试目录的路径,这样lua编译器会自动到这个目录寻找需要的文件。
这里是我用的目录Users/keyle/Desktop/LuaPlayground/?.lua
添加如下信息至 bash_profile 文件。

1
2
#LUA_PATH
export LUA_PATH="~/lua/?.lua;/Users/keyle/Desktop/LuaPlayground/?.lua;"

使用 source .bash_profile 命令使其生效

定义使用包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/local/bin/lua

complex = {} --包名需要与文件名同名

-- 私有函数
local function ptMethod(x)
print(x)
end

--实例函数
function complex.pt(content)
if content == nil then
ptMethod(complex.content)
else
print(content)
end
end

--实例变量
complex.content = "helloworld"

return complex

使用包

1
2
3
4
5
6
#!/usr/local/bin/lua

local c = require("complex") -- 使用require函数引入,我定义了一个局部变量 c 来接受这个包

c.pt() -- 调用别名为c的包内函数pt
c.pt("keyle")

元表

定义元表

方式一

1
2
3
table1 = {}
table1_meta = {}
setmetatable(table1,table1_meta)

方式二

1
setmetatable({},{})

使用元表查找

如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setmetatable(table1,table1_meta)

table_test = setmetatable({0,1,"three",2},{
__index = function (table,key)
print(key .. "<<<<")

if key=="great" then
return "meta_table_t"
end
end
})

print(table_test.great)
print(table_test[2])
print(table_test[3])

--great<<<<
--meta_table_t
--1
--three

使用元表赋值

这里使用元表提供的函数提前拦截赋值的地方。然后使用rawset进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
table_test =setmetatable({},
{
__newindex = function(tb,key,value)
print(key .. " <-UPDATE-> " .. value)
rawset(tb,key,value)
end
})

table_test.key = "key1"
print(table_test.key)

-- 输出结果
-- key <-UPDATE-> key1
-- key1

元表运算符重载

附录:元表中可重载的函数一览

符号 说明
add + 如果任何不是数字的值(包括不能转换为数字的字符串)做加法, Lua 就会尝试调用元方法。 首先、Lua 检查第一个数(即使它是合法的), 如果这个数没有为 “__add” 事件定义元方法, Lua 就会接着检查第二个数。 一旦 Lua 找到了元方法, 它将把两个数作为参数传入元方法, 元方法的结果(调整为单个值)作为这个的结果。 如果找不到元方法,将抛出一个错误
__sub - 行为和 “add” 类似
__mul * 行为和 “add” 类似
__div / 行为和 “add” 类似
__mod % 行为和 “add” 类似
__pow ^ 次方,行为和 “add” 类似
__unm - 取负,行为和 “add” 类似
__div / 向下取整除法,行为和 “add” 类似
__band & 按位与,行为和 “add” 类似, 不同的是 Lua 会在任何一个数无法转换为整数时 (参见 §3.4.3)尝试取元方法
__bor l 按位或,行为和 “band” 类似。
__bxor OR(binary ~) 按位异或,行为和 “band” 类似
__bnot NOT(unary ~) 按位非,行为和 “band” 类似
__shl << 按位非,行为和 “band” 类似
__shr >> 右移,行为和 “band” 类似
__concat .. 连接,行为和 “add” 类似, 不同的是 Lua 在任何数即不是一个字符串 也不是数字(数字总能转换为对应的字符串)的情况下尝试元方法
__len # 取长度,如果对象不是字符串,Lua 会尝试它的元方法。 如果有元方法,则调用它并将对象以参数形式传入, 而返回值(被调整为单个)则作为结果。 如果对象是一张表且没有元方法, Lua 使用表的取长度。 其它情况,均抛出错误
__eq == 等于,和 “add” 行为类似, 不同的是 Lua 仅在两个值都是表或都是完全用户数据 且它们不是同一个对象时才尝试元方法。 调用的结果总会被转换为布尔量
__lt < 小于,和 “add” 行为类似, 不同的是 Lua 仅在两个值不全为整数也不全为字符串时才尝试元方法。 调用的结果总会被转换为布尔量
__le <= 小于等于,和其它不同, 小于等于可能用到两个不同的事件。 首先,像 “lt” 的行为那样,Lua 在两个数中查找 “__le” 元方法。 如果一个元方法都找不到,就会再次查找 “__lt” 事件, 它会假设 a<= b等价于 not (b < a)。 而其它比较符类似,其结果会被转换为布尔量
__index 索引 table[key]。 当 table 不是表或是表 table 中不存在 key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。尽管名字取成这样, 这个事件的元方法其实可以是一个函数也可以是一张表。 如果它是一个函数,则以 table 和 key 作为参数调用它。 如果它是一张表,最终的结果就是以 key 取索引这张表的结果。(这个索引过程是走常规的流程,而不是直接索引, 所以这次索引有可能引发另一次元方法)
__newindex 索引赋值 table[key] = value 。 和索引事件类似,它发生在 table 不是表或是表 table 中不存在 key 这个键的时候。 此时,会读出 table 相应的元方法。同索引过程那样, 这个事件的元方法即可以是函数,也可以是一张表。 如果是一个函数, 则以 table、 key、以及 value 为参数传入。 如果是一张表, Lua 对这张表做索引赋值。 (这个索引过程是走常规的流程,而不是直接索引赋值, 所以这次索引赋值有可能引发另一次元方法。)一旦有了 “newindex” 元方法, Lua 就不再做最初的赋值。 (如果有必要,在元方法内部可以调用 rawset 来做赋值。)
call 函数调用 func(args)。 当 Lua 尝试调用一个非函数的值的时候会触发这个事件 (即 func 不是一个函数)。 查找 func 的元方法, 如果找得到,就调用这个元方法, func 作为第一个参数传入,原来调用的参数(args)后依次排在后面。

重载了+运算符 ,其他的同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
table_test =setmetatable({66,99,77},
{
__add = function(tb1,tb2)
for k,v in pairs(tb2) do
table.insert(tb1,k,v)
end
end
})

table3 = table_test+{33,44,11}

for k,v in pairs(table_test) do
print(k,v)
end

重载元表的 __call 与 __tostring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
table_test =setmetatable({66,99,77},
{
__call = function(tb1,tb2)
for k,v in pairs(tb2) do
table.insert(tb1,k,v)
end
end
})

table_test({33,44,11})

for k,v in pairs(table_test) do
print(k,v)
end
1
2
3
4
5
6
7
8
9
10
11
table1 = setmetatable({33,44,11},{
__tostring = function(tb1)
total = 0
for k,v in pairs(tb1) do
total = total + v
end
return "value total >> " .. total .. "<<<"
end
})

print(table1)

coroutine 协程

Lua 协同程序(coroutine) - 来自 RUNOOB.COM

  • coroutine.create() 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用
  • coroutine.resume() 重启coroutine,和create配合使用
  • coroutine.yield() 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果
  • coroutine.status() 查看coroutine的状态
    注:coroutine的状态有三种:dead,suspend,running,具体什么时候有这样的状态请参考下面的程序
  • coroutine.wrap() 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复
  • coroutine.running() 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/local/bin/lua

-- coroutine_test.lua 文件
co = coroutine.create(
function(i)
print(i);
end
)

coroutine.resume(co, 1) -- 1
print(coroutine.status(co)) -- dead

print("----------")

co = coroutine.wrap(
function(i)
print(i);
end
)

co(1)

print("----------")

co2 = coroutine.create(
function()
for i=1,10 do
print(i)
if i == 3 then
print(coroutine.status(co2)) --running
print(coroutine.running()) --thread:XXXXXX
end
coroutine.yield()
end
end
)

coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3

print(coroutine.status(co2)) -- suspended
print(coroutine.running())

print("----------")