lua 模块化的最佳实践

教程 shanhuhai 9144℃ 0评论

最近看了下 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 模块化的最佳实践

付费咨询
喜欢 (2)or分享 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址