15.5 其他一些技巧(Other Facilities)

正如前面我所说的,用表来实现packages过程中可以使用Lua的所有强大的功能。这里面有无限的可能性。在这里,我只给出一些建议。

我们不需要将package的所有公有成员的定义放在一起,例如,我们可以在一个独立分开的chunk中给我们的复数package增加一个新的函数:

function complex.div (c1, c2)

    return complex.mul(c1, complex.inv(c2))

end

(但是注意:私有成员必须限制在一个文件之内,我认为这是一件好事)反过来,我们可以在同一个文件之内定义多个packages,我们需要做的只是将每一个package放在一个do代码块内,这样local变量才能被限制在那个代码块中。

package外部,如果我们需要经常使用某个函数,我们可以给他们定义一个局部变量名:

local add, i = complex.add, complex.i

c1 = add(complex.new(10, 20), i)

如果我们不想一遍又一遍的重写package名,我们用一个短的局部变量表示package

local C = complex

c1 = C.add(C.new(10, 20), C.i)

写一个函数拆开package也是很容易的,将package中所有的名字放到全局命名空间即可:

function openpackage (ns)

    for n,v in pairs(ns) do _G[n] = v end

end

 

openpackage(complex)

c1 = mul(new(10, 20), i)

如果你担心打开package的时候会有命名冲突,可以在赋值以前检查一下名字是否存在:

function openpackage (ns)

    for n,v in pairs(ns) do

       if _G[n] ~= nil then

           error("name clash: " .. n .. " is already defined")

       end

       _G[n] = v

    end

end

由于packages本身也是表,我们甚至可以在packages中嵌套packages;也就是说我们在一个package内还可以创建package,然后很少有必要这么做。

另一个有趣之处是自动加载:函数只有被实际使用的时候才会自动加载。当我们加载一个自动加载的package,会自动创建一个新的空表来表示package并且设置表的__index metamethod来完成自动加载。当我们调用任何一个没有被加载的函数的时候,__index metamethod将被触发去加载着个函数。当调用发现函数已经被加载,__index将不会被触发。

下面有一个简单的实现自动加载的方法。每一个函数定义在一个辅助文件中。(也可能一个文件内有多个函数)这些文件中的每一个都以标准的方式定义函数,例如:

function pack1.foo ()

    ...

end

 

function pack1.goo ()

    ...

end

然而,文件并不会创建package,因为当函数被加载的时候package已经存在了。

在主package中我们定义一个辅助表来记录函数存放的位置:

local location = {

    foo = "/usr/local/lua/lib/pack1_1.lua",

    goo = "/usr/local/lua/lib/pack1_1.lua",

    foo1 = "/usr/local/lua/lib/pack1_2.lua",

    goo1 = "/usr/local/lua/lib/pack1_3.lua",

}

下面我们创建package并且定义她的metamethod

pack1 = {}

 

setmetatable(pack1, {__index = function (t, funcname)

local file = location[funcname]

if not file then

    error("package pack1 does not define " .. funcname)

end

assert(loadfile(file))()    -- load and run definition

return t[funcname]          -- return the function

end})

 

return pack1

加载这个package之后,第一次程序执行pack1.foo()将触发__index metamethod,接着发现函数有一个相应的文件,并加载这个文件。微妙之处在于:加载了文件,同时返回函数作为访问的结果。

因为整个系统(译者:这里可能指复数吧?)都使用Lua写的,所以很容易改变系统的行为。例如,函数可以是用C写的,在metamethod中用loadlib加载他。或者我们我们可以在全局表中设定一个metamethod来自动加载整个packages.这里有无限的可能等着你去发掘。

 

 



相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛