最近看了下 lua 的模块化机制,有好几种实现方式,有些东西都很老旧了,对于新手来说实在没必要了解了,下面我们直接看看 lua 模块化的最佳方式。
其实可以参考仓库 openresty 里提供的各种包,这些包用的都是最佳方式,例如
lua-resty-redis
方式一 通过返回表来实现
local M = {}
function M.play()
print("开始");
end
function M.quit()
print("退出")
end
return M;
调用:
local game = require('game')
game.play()
方式二 在包中定义类
local _M = {}
_M._VERSION = '1.0'
local mt = { __index = _M }
function _M.new(self, width, height )
return setmetatable({width = width, height = height}, mt)
end
function _M.get_square( self )
return self.width * self.height
end
return _M
调用:
local square = require('square')
local s1 = square:new(2, 3)
print(s1:get_square())
lua 参数默认值
lua 的函数参数不支持默认值,可以通过间接的方式来实现
function output(msg)
msg = msg or "Hello"
print(msg)
end
setmetatable() 和元表
lua 的面向对象编程中有一个中重要的概念 metatable (元表)。
- 任何 table 都可以附加元表
- setmetatable()用来将一个表附给另一个表做元表, 该函数总是返回第一个参数
- 元表里可以包含任何东西,常用的索引是
__index
和__newindex
- 索引对应的值可以是 表或者函数
t = {} -- 普通表
mt = {} -- 元表暂时为空
t = setmetatable(t, mt) -- 将 mt 设为 t 的元表
__index 索引
先测试一段代码
_M = {
name = "shanhuhai"
}
local mt = {__index = _M , name = "yyyy" }
person = setmetatable({},mt)
print(person.name)
print(person['name'])
对照上面的代码,当我们通过索引来访问表比如person.name
, lua 会先查找当前表已有的索引,接着查找它的元表 mt
的 __index
索引, __index
对应的表是 _M
, 在 _M
中找到了 name
索引,则返回了对应的值。
__newindex
_N = {
name = "shanhuhai"
}
person = {
__index = mt
}
local mt = {__newindex = _N }
person = setmetatable({},mt)
person.sex = 1
print(_N.sex)
对表的索引赋值时,由于在表中找不到 sex 索引,且在元表的 __index
对应的表也找不到对应的索引,这时就会在__newindex
索引对应的表中添加此索引并斌值。
总结
Lua 的 module 有两种类型:静态方法提供者,没有任何私有属性(方式一);支持面向对象可以保留私有属性(方式二);真正起到区别作用的就是 setmetatable 函数,是否有自己的个性元表,最终导致两种不同的形态。
参考文章
http://www.cnblogs.com/xdao/archive/2013/04/02/lua-metatable.html
https://moonbingbing.gitbooks.io/openresty-best-practices/lua/not_use_module.html
https://moonbingbing.gitbooks.io/openresty-best-practices/lua/module_is_evil.html
转载请注明:大后端 » lua 模块化的最佳实践