zoukankan      html  css  js  c++  java
  • 《Programming in Lua 3》读书笔记(十一)

    日期:2014.7.11

    Part Ⅱ Modules and Packages

    模块(module)是一些(既不是lua也不是c)能被函数require加载的代码,这些代码的作用在于创建并返回table。这个模块输出的函数、常量等都是定义在这个table中,其工作原理类似于命名空间。

    Lua中所有的标准库都是模块,使用方法:
    e.g.
    local  m = require "math"
    print(m.sin(3.14))

    Lua中可以将模块存储在table中,或者作为函数的参数使用;

    require函数的限制在于,不能给要加载的模块传递参数。

    模块本身只能加载一次


    The require Function
    用require函数load模块的时候,该函数首先会从package.loaded这个table中检查该模块是否已经被加载了:此时模块的名字假定叫做modname
    如果该模块已经被加载了,则返回已经被加载的值。所以,一旦某个模块已经被加载了,其他任何再需要加载该模块都是返回同样的值,不会再重新加载。
    而如果该模块未被加载,则该函数会根据该模块的名字去搜索Lua文件,如果寻找到了就用loadfile函数加载,loadfile函数加载文件会返回一个函数,我们称该函数为一个loader。
    如果require函数未从Lua文件中寻找到该模块,则会转向C库去寻找。如果在C库中寻找到了,该函数会用package.loadlib,调用一个luaopen_modname的函数去加载,此时的loader是loadlib的执行结果,而函数luaopen_modename则代表一个lua函数。
    require函数通过两个参数调用loader:模块的名字和得到loader的文件的名字。require函数会返回loader所返回的任何值,并且将值存储至package.loaded 这个table中,今后所有对该同名模块的加载都会从这个table中得到。如果loader没有返回任何值,系统为了防止之后再一次加载该模块,require函数会认为该模块返回了true。
    当我们想强制重新加载一次一个已加载了的模块,最简单的做法是将该模块的值从package.loaded 这个table中擦除掉:

    这样在下一次需要加载该模块的时候,就会重新加载一次。


    Renaming a module
    重命名一个模块

    一般情况下我们会用模块的原有名字来使用模块,但是为了防止命名冲突我们不得不重新命名某些模块。模块命名的时候采用连字符。Lua会require内部的操作函数会自动使用连字符后面的命名来操作模块的加载,如模块命名为:
    e.g.
    m = require "v1-mod"

    而实际上内部的luaopen_(这里是模块名)函数会使用这样的命名:
    luaopen_mod


    Path searching
    路径搜索

    require的搜索路径与一般情况下的不同。ANSI C(lua 运行的平台)中没有目录这一概念。因此require所用的路径是一串模板,每个模板都指定了一个将模块名转换成文件名的方式。具体来看就是一个一个问号组成,每个模板下require都会将模块名曲代替这些问号,然后去检测是否符合要求:
    ?;?.lua?c:windows?
    --假如此时模块名为 mod ,将会被转换成 
    mod;mod.lua;cwindowsmod
    Lua代码中path是从 package.path 中得到的
    而在C库中搜索用到的path 则是从 package.cpath 中得到的。

    函数package.searchpath 替搜索库将上述各种规则都封装好了,该函数接受两个参数,一个是模块名,一个是搜索路径。遵循以上的搜索规则执行搜索工作。该函数的返回值是:如果该模块存在则返回其存在的信息,否则返回nil加上错误信息。
    e.g.
    path = ".\?.dll;C:\ProgramFiles\Lua502\dll\?.dll"
    print(package.searchpath("X",path))
    --打印信息
    nil    
         no file '.X.dll'
         no file 'C:ProgramFilesLua502dllX.dll'


    Searchers
    事实上require函数比我们上述介绍的要更为复杂。这里要引申出一个概念 searchers。一个searcher就是一个函数,接受模块名作为参数然后为该模块返回一个loader或者当该模块不存在的时候返回nil。
    package.searchers 里面列举了require函数所用到的searchers。require就是用这些searchers去寻找的。



    The Basic Approach for Wirting Modules in Lua
    Lua中写模块的方法

    最简单的方法便是新创建一个table,然后将我们要用到的函数存储至该table,然后返回这个table。

    简单的实现一个模块:
    local M = {}
    
    function M.new(r,i) return {r = r,i = i} end
    --define constant "i"
    M.i = M.new(0,1)
    
    function M.add(c1,c2)
         return M.new(c1.r + c2.r,c1.i + c2.i)
    end
    
    function M.sub(c1,c2)
         return M.new(c1.r - c2.r,c1.i -c2.i)
    end
    
    function M.mul(c1,c2)
         return M.new(c1.r*c2.r - c1.i*c2.i,c1.r*c2.i + c1.i*c2.r)
    end
    
    local function inv(c)
         local n = c.r^2 +c.i^2
         return M.new(c.r/n,-c.i/n)
    end
    
    function M.div(c1,c2)
         return M.mul(c1,inv(c2))
    end
    
    function M.tostring(c)
         return "(" .. c.r .. "," .. c.i .. ")"
    end
    
    return M           --返回模块

    --其实不是很懂。。。。


    Using Environment
    在模块中通过改变环境来避免对全局环境带来影响。
    要注意当我们在自己的模块中改变了_ENV的时候,将会对其余的模块产生影响,因此我们在改变_ENV之前需要做一些处理。
    e.g.
    local M = {}
    setmetatabel(M,{__index = _G})
    _ENV = M 

    这种情况下,M模块就包含了所有的全局变量了。
    or
    local M = {}
    local _G = _G
    _ENV = M


    这种方式下,我们使用全局变量的时候要加上前缀_G,这种方式也带来了更快的运行速度,因为没有涉及到元方法的使用。

    还有一种方法就是将模块中需要使用的函数定义为局部的
    e.g.
    local M = {}

    --将需要使用的定义为局部变量
    local sqrt = math.sqrt
    local io = io
    <span style="font-family: Verdana; font-size: 18px; orphans: 2; widows: 2;">_ENV = nil</span>
    

    这种方式也能带来更快的运行速度。


    Submodules and Packages
    子模块

    Lua 允许使用句点符号来实现模块的分层。如,一个模块mod.sub 就是mod模块的子模块。一个package就是一个模块的树。
    reuqire函数在搜索的时候,会将句点符号做一定的转换-使用系统目录分隔符(UNIX下使用"/",windows下使用"")
  • 相关阅读:
    Oracle数据库中truncate命令和delete命令的区别
    数组中只出现一次的数字
    数对之差的最大值
    SQL Server: Difference Between Locking, Blocking and Dead Locking
    字符串处理
    Phpcms_V9任意文件上传
    最初的梦想
    陪你走过漫长岁月
    基于MitM的RDP降级攻击
    CVE-2017-0358
  • 原文地址:https://www.cnblogs.com/zhong-dev/p/4044575.html
Copyright © 2011-2022 走看看