module函数

模块的基本编写方法

local M = {}
local modname = 'a'
_G[modname] = M
package.loaded[modname] = M

function M.play()
	print('play')
end

function M.say()
	print('say')
	M.play()
end

return M

这里的问题是模块内函数之间的调用仍然要保留模块名的限定符,比如say中调用play方法就需要M.play。

使用环境

解决上面那个问题可以用setfenv把当前模块的全局环境设置为M,于是,定义函数的时候就不用加上M,模块中函数间的调用也不需要加M限定。

local M = {}
local modname = 'a'
_G[modname] = M
package.loaded[modname] = M
setfenv(1, M)

function play()
	-- print('play')
end

function say()
	-- print('say')
	play()
end

return M

上面把print注释掉了,是因为这个时候调用play或者say方法会报错,大概是说没有print这个东西。因为当前的全局环境变了,不是_G而是M,M中当然没有print。那要如何使用到_G中的全局变量呢?元表。

local M = {}
local modname = 'a'
_G[modname] = M
package.loaded[modname] = M

setmetatable(M, {__index = _G})
setfenv(1, M)

使用module

可以使用module函数来替换下面的代码

local M = {}
local modname = 'a'
_G[modname] = M
package.loaded[modname] = M

setfenv(1, M)

上面的可以简化为

module('a')

module默认是不提供外部访问的,也就是说这个时候print这些还是不能用的。

如果要加上setmetatable(M, {__index = _G})的效果,需要加上package.seeall参数,如

module('a', package.seeall)

稍微一个总结:使用module来创建模块,定义函数以及模块内函数间的调用都可以不用加上限定附,比如上面的M。还有就是可以不用写return M,以及可以访问到_G中的全局变量。

附:

setfenv(f, table):设置一个函数的环境

  (1)当第一个参数为一个函数时,表示设置该函数的环境

  (2)当第一个参数为一个数字时,为1代表当前函数,2代表调用自己的函数,3代表调用自己的函数的函数,以此类推

  所谓函数的环境,其实一个环境就是一个表,该函数被限定为只能访问该表中的域,或在函数体内自己定义的变量。

原文地址:https://www.cnblogs.com/i-love-kobe/p/8488849.html