• lua module环境探秘


    module 作用

    module (name [, ···])

    Creates a module. If there is a table in package.loaded[name], this table is the module. Otherwise, if there is a global table t with the given name, this table is the module. Otherwise creates a new table t and sets it as the value of the global name and the value of package.loaded[name]. This function also initializes t._NAME with the given name, t._M with the module (t itself), and t._PACKAGE with the package name (the full module name minus last component; see below). Finally, module sets t as the new environment of the current function and the new value of package.loaded[name], so that require returns t.

    http://blog.csdn.net/chenyufei1013/article/details/4438801

    当在模块文件中使用module函数的时候,如下所示;

    module “mymodule”

    。。。

     

    实际上等同于以下的语句:

    local modname = “mymodule”     – 定义模块名
    local M = {}                               -- 定义用于返回的模块表
    _G[modname] = M                      -- 将模块表加入到全局变量中
    package.loaded[modname] = M    -- 将模块表加入到package.loaded中,防止多次加载
    setfenv(1,M)                               -- 将模块表设置为函数的环境表,这使得模块中的所有操作是以在模块表中的,这样定义函数就直接定义在模块表中

    。。。

    return M

    module被require后返回的对象

    整个module文件, 可以看做是一个函数,详见lua chunk解释:

    http://www.lua.org/manual/5.1/manual.html

    2.4.1 – Chunks

    The unit of execution of Lua is called a chunk. A chunk is simply a sequence of statements, which are executed sequentially. Each statement can be optionally followed by a semicolon:

    	chunk ::= {stat [`;´]}
    

    There are no empty statements and thus ';;' is not legal.

    Lua handles a chunk as the body of an anonymous function with a variable number of arguments (see §2.5.9). As such, chunks can define local variables, receive arguments, and return values.

    从上可以看出, module改变了匿名函数的行为, 返回的是 module构造的局部表(env), 此表在module文件中定义, 然后在module声明之后的语句执行前, 被设置为整个匿名函数的环境, 待module声明之后的语句全部执行完毕, (非local的一些变量, 则会在运行环境env中记录下来, 这个变量相对local来说是开放的,开放到环境中, local变量则生存在匿名函数中, 函数运行结束, 则local消失, 但是env中记录的非local变量得以保存)。

    module中如何设置key为变量值的元素

    在module文件中, 由于其运行环境是隐式的, 代码中无法直接同名字面量来引用到这个环境, 那么对于一种特殊情况, 需要在环境中记录一些key-value对, 但是key是来自于变量, 如何实现?

    由于整个文件是一个chunk, 即匿名函数, 故可以借助getfenv,来获取运行环境。

    local strkey = "vartwo"


    -- 本模块环境
    local env = getfenv(1)

    env[strkey] = 2

    module中如何引用调用者的环境

    既然module文件是一个chunk对应一个一名函数, 则可以通过getfenv(2), 来获取此函数的调用者,

    即谁require此文件的函数, 这个函数运行的环境, 即为调用者环境。

    -- 调用此模块的环境
    local env_caller = getfenv(2)

    env["env_caller"] = env_caller

    实验代码

    module_test.lua

    module(..., package.seeall)


    varone = 1

    local strkey = "vartwo"


    -- 本模块环境
    local env = getfenv(1)

    env[strkey] = 2

    print("vartwo="..vartwo)

    -- 调用此模块的环境
    local env_caller = getfenv(2)

    env["env_caller"] = env_caller

    main.lua


    local testmodule = require("module_test")

    var_caller = 55

    print("testmodule.vartwo=" .. testmodule.vartwo)


    local function printTable(tbl)

        for k,v in pairs(tbl) do
            print("kay="..tostring(k) .. "  value="..tostring(v))
        end

    end


    print("----------- testmodule ------------------")

    printTable(testmodule)

    print("-----------  testmodule.env_caller ------------------")

    printTable(testmodule.env_caller)

    运行输出结果:

    >lua -e "io.stdout:setvbuf 'no'" "main.lua"
    vartwo=2
    testmodule.vartwo=2
    ----------- testmodule ------------------
    kay=_NAME  value=module_test
    kay=_PACKAGE  value=
    kay=varone  value=1
    kay=_M  value=table: 005F9410
    kay=vartwo  value=2
    kay=env_caller  value=table: 005F2650
    -----------  testmodule.env_caller ------------------
    kay=string  value=table: 005F9398
    kay=xpcall  value=function: 005F6CE8
    kay=module_test  value=table: 005F9410
    kay=package  value=table: 005F7160
    kay=tostring  value=function: 005F6CC8
    kay=print  value=function: 005F6808
    kay=os  value=table: 005F95A0
    kay=unpack  value=function: 005F6AE8
    kay=require  value=function: 005F8078
    kay=getfenv  value=function: 005F6788
    kay=setmetatable  value=function: 005F6C48
    kay=next  value=function: 005F66E8
    kay=assert  value=function: 005F68A8
    kay=tonumber  value=function: 005F6CA8
    kay=io  value=table: 005F94D8
    kay=rawequal  value=function: 005F6828
    kay=collectgarbage  value=function: 005F6668
    kay=arg  value=table: 005F92D0
    kay=getmetatable  value=function: 005F6688
    kay=module  value=function: 005F7FD8
    kay=rawset  value=function: 005F6A28
    kay=var_caller  value=55
    kay=math  value=table: 005F9348
    kay=debug  value=table: 005F90F0
    kay=pcall  value=function: 005F6988
    kay=table  value=table: 005F72C8
    kay=newproxy  value=function: 005F0568
    kay=type  value=function: 005F6D08
    kay=coroutine  value=table: 005F70C0
    kay=_G  value=table: 005F2650
    kay=select  value=function: 005F6708
    kay=gcinfo  value=function: 005F69E8
    kay=pairs  value=function: 005F0538
    kay=rawget  value=function: 005F6908
    kay=loadstring  value=function: 005F67C8
    kay=ipairs  value=function: 005F2BD0
    kay=_VERSION  value=Lua 5.1
    kay=dofile  value=function: 005F67A8
    kay=setfenv  value=function: 005F6A08
    kay=load  value=function: 005F6888
    kay=error  value=function: 005F6768
    kay=loadfile  value=function: 005F6848
    >Exit code: 0

  • 相关阅读:
    如何实现1080P延迟低于500ms的实时超清直播传输技术
    直播体验深度优化方案——连麦互动直播
    前向纠错码(FEC)的RTP荷载格式
    C++通过COM接口操作PPT
    neo4j的搭建和实例使用
    【neo4j】neo4j Desktop1.1.9,windows 安装
    Neo4j删除节点和关系、彻底删除节点标签名
    知识图谱赵军学习笔记(五)--实体消歧
    实体消歧简介
    svn服务器时间与本地时间不同步解决
  • 原文地址:https://www.cnblogs.com/lightsong/p/5743135.html
Copyright © 2020-2023  润新知