zoukankan      html  css  js  c++  java
  • Chapter 15_1 require函数

      Lua提供了一个名为require的高层函数来加载模块,但这个函数只假设了关于模块的基本概念。

    对于require而言,一个模块就是一段定义了一些值(函数或者包含函数的table)的代码。

    为了加载一个模块,只需要简单调用require "modname" 。这个函数首先会查找package.loaded表,检查modname是否加载过。

    如果加载过,require返回package.loaded[modname]中的值。

    否则,它试着为模块寻找“加载器”。

    首先require会搜寻Lua file 。如果找到lua文件,就调用loadfile加载,它的返回值是函数 即"加载器"。

    如果找不到Lua文件,会寻找C库,如果找到,就调用package.loadlib加载,去寻找luaopen_modname标志函数。

    每次找到加载器,require就用两个参数调用加载器:modname和一个在获取加载器过程中得到的参数(如果通过查找文件得到的加载器,这个额外参数就是文件名)。

    如果加载器返回非空值,require将这个值赋给package.loaded[modname].否则也会为其设置true值,无论什么情况,require都会返回package.loaded[modname]的最终值。如果在加载或运行时有错误,或是无法为模块找到加载器,require都会抛出错误。

    如果要用require加载模块两次,我们可以把package.loaded[modname]给擦除掉。

    packag.loaded.[modname] = nil

    有时需要讲一个模块改名,以避免名字冲突。比如同一个模块有不同版本的情况。对于一个lua文件来说,改掉名字就可以了。

    但是对于一个C程序库,我们就不能编辑其中的luaopen_*函数的名称了。为此,require用到了一个小技巧:

    如果一个模块中包含了连字符 " - " ,require就会用连字符后的内容来创建luaopen_*函数名。

    比如一个模块名为module-hello,require就会认为它的open函数是luaopen_hello,并不是luaopen_a-b

    因为在C语法中,连字符作为函数名是非法的。

    因此,如果我们需要用两个同名的mod模块,可以把其中一个重新命名为mod-hello,一个命名为mod-world。

    当调用

    m1 = require "mod-hello"

    require函数会找到这个mod-hello文件,并且在这个文件里,去找luaopen_mod函数。

    注意:Lua5.2与Lua5.3这里是完全相反:5.2移除"-"之前的,5.3移除“-”之后的。

    Lua5.3的版本,如果遇到a.b.c-v2.1的模块名,函数名就是luaopen_a_b_c。横线后的都忽略掉

    路径搜索

      当搜索一个Lua文件的时候,rquire用的的路径是一系列样板(templates),其中的每一个指定了模块的文件名。

    在每个路径样板中都包含了一个可选的'?'符号,require会用模块名去替代这个问号(如果有的话),再去检查这个文件是否存在。

    如果该样板没有,就从下一个样板继续寻找。这些路径样板被";"一个个隔开:

    ?;?.lua;c:Windows?;/usr/local/lua/?/?.lua

    require "mod" 语句会寻找下面的文件:

    mod
    mod.lua
    c:Windowsmod
    /usr/loacl/lua/mod/mod.lua

    require只处理 ";" 和 "?" 符号,其他符合则是路径自己定义的。

    require找lua文件时路径变量是package.path。Lua一开始会用LUA_PATH_5_3环境变量去初始化它。

    如果没有定义这个环境变量,就会用LUA_PATH。如果两个都没有定义,Lua会用luaconf.h里的默认路径。

    环境变量中出现的所有“;;”都会被替换成默认路径。

    比如你把LUA_PATH_5_3设置为“mydir/?.lua;;”,最后的路径会是"mydir/?.lua"之后跟着的是默认路径。

    require寻找C库的方法也是一样的,但是变量变成了package.cpath。初始化的时候使用的是LUA_CPATH_5_3和LUA_CPATH。

    在UNIX中是这样的:

    ./?.so;/usr/local/lib/lua/5.3/?.so

    package.searchpath函数包含了所有搜寻库的规则,它接收一个模块名和一个路径。

    路径是一系列以分号分隔的模板构成的字符串,在其中搜索指定的name。

    返回第一个可以用读模式打开(并马上关闭该文件)的文件的名字。如果不存在这样的文件,即返回nil加上错误消息。

    该错误消息列出所有尝试打开的文件名。

    搜寻器

      用于require控制如何加载模块的表--package.searchers

    表内的每一项都是一个查找器函数,当查找一个模块时,require按照次序调用这些查找器,并传入唯一的模块名参数。

    成功则返回另一个函数(模块的加载器)和一个加载器需要的参数。nil则表示错误。

    Lua用四个查找器函数初始化该表:

    1>  在package.preload表中查找加载器,没有返回值。

    2>  查找Lua库的加载库,用存储在package.path中的路径来查找

    3>  查找C库的加载库,使用存储在package.cpath中的路径。

    4>  一体化加载器,从C路径中查找指定模块的根名字。例如“a.b.c”;它将查找a这个库。如果找到就会在里面找子模块的加载函数,就是找luaopen_a_b_c。

    比如查找 “hello.core” 模块,就是寻找hello库的core子模块。对应的函数就是luaopen_hello_core。

    这样可以把若干C子模块打包进单个库。每个子模块都可以有原本的加载函数名。

     以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition 》

  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/daiker/p/5865709.html
Copyright © 2011-2022 走看看