• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Lua笔记——5.环境Environment

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

与储存在lua解释器中特殊数据结构里的本地变量不同,全局变量储存在一个表table中。而Lua的一个非常有用的特性就是每个function都可以去改变这个table,这些table中的每一个都称之为一个环境environment。所以改变了这个表的function可以看到一组不同的全局变量。

Lua的默认全局环境即默认的全局表使用"_G"索引储存在它自己内部,Lua5.1和5.2之后版本中环境的工作方式非常不同

Environments in Lua 5.2

  • Lua 保留一个独特的环境称之为全局环境,它的值保存在C 注册表中的一个特定索引中。在Lua里,变量_G被该值初始化称为全局环境。
  • 当Lua编译一个代码块,该代码块会被设置一个外部的局部变量_ENV(在一个代码块中_ENV本身并不是一个全局的名称)它会用全局环境_G 初始化该代码块的外部的局部变量_ENV upvalue。因此,代码块中任何一个对全局变量var的引用都会被语法转换为_ENV.var(默认的话即是_G.var)。
  • Lua中全部的标准库都在全局环境_G中被加载并且一些函数语句会被运行在全局环境中。可以使用load或者loadfile来加载代码块到一个不同的环境。任何一个被用作_ENV的值的table都称之为一个环境environment。

当Lua编译或者load一个代码块等同于代码:

--every chunk is compiled in the scope of an external local variable called _ENV
local _ENV = _G
return function (...) -- this is the function what's returned from load
    -- code you passed to load goes here, with all global variable names replaced with _ENV to lookups
    -- so, for example "a = b" becomes "_ENV.a = _ENV.b" if neither a nor b were declared local
end

_ENV:

--file: testEnv.lua

x = 300
y = 100

print(_ENV == _G)   -- prints true, since the default _ENV is set to the global table

print("pos x : " .. x .." pos y : " .. y)   -- pos x : 300 pos y : 100

local function setEnv(t)
    assert(type(t) == "table" , "Notice: The env you pass ".. type(t) .." is not a table .")
    local print = print
    local _ENV = t
    --get the local variable x , y  and print , as same as _ENV.x , _ENV.y , _ENV.print
    print("pos x : " .. x .." pos y : " .. y)   -- pos x : 800 pos y : 500
end

local env = {x =800 , y = 500 }
setEnv(env)

print("pos x : " .. x .." pos y : " .. y)   -- pos x : 300 pos y : 100

load (ld [, source [, mode [, env]]])

Loads a chunk.

If ld is a string, the chunk is this string.

If ld is a function, load calls it repeatedly to get the chunk pieces. Each call to ld must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.

If the resulting function has upvalues, the first upvalue is set to the value of env, if that parameter is given, or to the value of the global environment. (When you load a main chunk, the resulting function will always have exactly one upvalue, the _ENV variable . When you load a binary chunk created from a function , the resulting function can have arbitrary upvalues.)

source is used as the source of the chunk for error messages and debug information . When absent, it defaults to ld, if ld is a string, or to "=(load)" otherwise.

The string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string "b" (only binary chunks), "t" (only text chunks), or "bt" (both binary and text). The default is "bt".

In most cases, you don't need to use environments, unless you want to sandbox a loaded chunk, to give it convenient access to certain functions by making them look global, or to prevent it from seeing unsafe functions for security reasons. This is why 5.2's load function takes a parameter that lets you set the chunk's _ENV to a custom table, instead of_G.

loadfile ([filename [, mode [, env]]])

Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.

案例代码:

--file :testSandEnv.lua

local sandEnv = { os = os , print = print , _VERSION = _VERSION }

local func = load("print(_VERSION);print(os.execute());","loadSandEnv",nil,sandEnv)

if func == nil then
    error("Invalid syntax.")
end

func()

运行结果:

Environments in Lua 5.1

  • 每个function都可以有一个环境table与之相关联,并且可以通过setfenv以及getfenv来改变或者得到这个环境表
--file: testEnv.lua

x = 300
y = 100
print("pos x : " .. x .." pos y : " .. y)   -- pos x : 300 pos y : 100

function setEnv(t)
    assert(type(t) == "table" , "Notice: The env you pass ".. type(t) .." is not a table .")
    local print = print
    setfenv(1,t)
    print("pos x : " .. x .." pos y : " .. y)   -- pos x : 800 pos y : 500
end

local env = {x =800 , y = 500 }
setEnv(env)

print("pos x : " .. x .." pos y : " .. y)   -- pos x : 300 pos y : 100

load (func [, chunkname])

Loads a chunk using function func to get its pieces. Each call to func must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.

If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

chunkname is used as the chunk name for error messages and debug information. When absent, it defaults to "=(load)".

loadfile ([filename])

Similar to load, but gets the chunk from file filename or from the standard input, if no file name is given.

loadstring (string [, chunkname])

Similar to load, but gets the chunk from the given string.

To load and run a given string, use the idiom

assert(loadstring(s))()

When absent, chunkname defaults to the given string.

沙盒环境代码:

--file :testSandEnv.lua

local sandEnv = { os = os , print = print , _VERSION = _VERSION }
local func = loadstring("print(_VERSION);print(os.execute());" , "loadSandEnv")

setfenv(func,sandEnv)

func()

Usage

兼容代码:

-- Run a Lua script in a separate environment
local function run_script(script, env)
    local env = env or {}
    local func

    -- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists
    if _G.setfenv then
        func = loadstring(script)
        if func then
            setfenv(func, env)
        end
    else
        func = load(script, nil, nil, env)
    end

    if func == nil then
            error("Invalid syntax.")
    end
    func()

    return env
end

总结

The 5.1 way is sometimes considered simpler and more versatile, but it also requires special treatment of environments (instead of using the existing local variable system). Also, the 5.2 way is designed with the idea that a function's environment is supposed to be private, instead of being accessible from everywhere without the debug library, so it can be considered safer.

Lua5.1的方法有时候会被认为更加的简单和多功能,但是它也需要对环境做出特殊的处理(替代现有的局部变量系统)。而Lua5.2方法是认为函数的环境应该为私有的理念来设计的,而不是在不需要调试库的情况下从任何地方都可以访问,因此可以认为Lua5.2的方法更加安全。

REF

http://lua-users.org/wiki/EnvironmentsTutorial

http://www.ogeek.net/article/55816.htm

http://blog.csdn.net/xenyinzen/article/details/3485633


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
lua脚本string.find查找关于()的问题发布时间:2022-07-22
下一篇:
区别Lua模式匹配中%a+与.-发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap