zoukankan      html  css  js  c++  java
  • module require区别

    LUA modue require package 区别  

    2011-01-19 12:41:35|  分类: 默认分类 |  标签:lua  package  module  require  加载  |字号 订阅

     
     

    【lua 5.1 的 module】

    lua 从 5.1 开始终于官方提供统一的 module 实现标准了,这是个值得庆幸的事。今天读了下相关的源码和文档,把这套机制搞清楚了,还是很巧妙的。从简洁这个角度看,要比 python 强 :)

    有一点容易被忽略掉(我的同事在用的时候就忽略掉了),module 指令运行完后,整个环境被压栈,所以前面全局的东西再看不见了。比如定义了一个 test 模块,使用

    module("test")

    后,下面不再看的见前面的全局环境。如果在这个模块里想调用 print 输出调试信息怎么办呢?一个简单的方法是

    local print=print
    module("test")

    这样 print 是一个 local 变量,下面也是可见的。或者可以用

    local _G=_G
    module("test")

    那么 _G.print 也是可以用的。

    当然还有一种巧妙的方式,lua 5.1 提供了一个 package.seeall 可以作为 module 的option 传入

    module("test",package.seeall)

    这样就 OK 了。至于它们是如何工作的,还是自己读源码会理解的清楚一些。

    在读源码时可以发现很多 lua 的技巧,还有一些 undocumented 的东西,比如 newproxy :) 它是一个 unsupported 且 undocumented 的东西,但是它希望实现的却是个巧妙的玩意。

    总结:

    功能:建立一个模块。

      当package.loaded[name]中存在时,当中的表作为module;

      当在全局表中存在name指定的表时,此表作为module;

      当以前两种情况都不存表name时,将新建一个表,并使其作为全局名name的值,并package.loaded[name],而且设 t._NAME为name,t._M为module,t._PACKAGE为包的全名(模块名-组件a.b.c);最后把此module设t作为当前函数 的新环境表和package.loaded[name]的新值(也就是说,旧的环境表将不能访问,除了加上package.seeall参数外),以被 require使用

      module(name)后的可选参数为接收module名的函数,如package.seeall

      

       

    【lua 5.1 的 require】

        require (modname)

      功能:加载指定的模块。

      此函数先检测package.loaded表中是否存在modname,存在则直接返回当中的值,没有则通过郰定义的加载器加载modname。

      查找加载器顺序:

      (1)检测package.preload表是否存在modname,有则加载

      (2)通过Lua Loader加载,通过查找存放于package.path的路径加载,有则加载

      (3)通过C Loader加载,通过查找存放于package.cpath的路径加载,有则加载

      (4)通过all-in-one Loader加载:

      通过查找modname.dll并查找当中的luaopen_

      其中XXXX为载块名-后的字符用_替换.后的字符:如:a.v1-b.c 当函数名为luaopen_b_c

      当require查找的不是一个Lua库或C库,它就会调用all-in-one loader,此加载器是用C路径作为载块的目录,

      当查找到合适的加载器时,require就会加载其中的模块,当加载器有返回值,将会存放于package.loaded[modname]表。最后返回package.loaded[modname]表

      当加载失败时,require将触发错误

      3、package.cpath

      功能:用于require C loader的搜索路径

      可以通过修改LUA_CPATH变量(luaconf.h)修改此值

      4、package.loaded

      功能:一个用于让require知道哪些模块已加载的记录表,如果package.loaded已经有require要的值,则直接返回此值

      5、package.loadlib (libname, funcname)

      功能:通过动态连接C函数库方式加载Lua扩展库

      libname为库文件名,funcname为入口函数(此函数必须为纯C接口函数 c++则需用 extern "C" {} 进行限制)

      6、package.path

      功能:用于require Lua loader的搜索路径

      可以通过修改LUA_PATH变量(luaconf.h)修改此值

      7、package.preload

      功能:一个用于保存特殊模块加载器的表

      8、package.seeall(module)

      功能:为module设置一个元表,此元表的__index字段的值为全局环境_G。所以module可以访问全局环境

      注:以此函数作为module()的一个选项(详细见module()

    注意:require只认文件名,不认路径名。要加入路径名信息的话,就要写成父模块子模块的形式。

    比如说,我有两个文件夹 testa, testb,在每个文件夹里面都有一个run.lua文件。我先在lua里面chdir进到testa里面去require了一下run.lua,然后再 chdir出来,再chdir进testb,然后,再执行require "run"。

    这个时候,Lua是默认不会把第二个文件夹中的 run.lua给加载进来的,因为Lua会对加载进来的所有模块有一个按名字的管理系统,记录在 package.loaded 里面。如果要强制加载新的run.lua文件,就得把老的模块记录给清掉,即使用 package.loaded["run"] = nil,然后再加载。

    实际上,Lua这样设计的目的是为了防止对模块的重复加载──这样可以解决开发过程中经常遇到的重复包含的问题,还可解决递归包含的问题。我们通常在C语言的头文件中写上#ifdef #define #endif之类的结构,也是为了实现这种效果。

    任何设计都不是万能的,需要开发者根据实际情况灵活变通。

  • 相关阅读:
    spring@Async注解实现异步方法调用
    mysql锁机制
    springboot启动时执行任务CommandLineRunner
    java-并发编程之fork/join框架
    mysql explain 执行计划详解
    mysql 时间相关sql , 按天、月、季度、年等条件进行查询
    swagger2 常用注解说明
    VirtualBox 安装CentOS虚拟机网卡配置
    RestFul是啥
    文本内文字字数过多,显示省略号
  • 原文地址:https://www.cnblogs.com/ghost240/p/3275433.html
Copyright © 2011-2022 走看看