k) --> 10100110 end function factory (_ENV) local i = j + k

更多的应该不污染全局环境, env.name) --> 加载的模块的 name :将 name 进行篡改 via loadfile 被加载的 config .lua width = 1000 height = 1000 print (name) --> nil (因为上面的代码没有将 _G 传入, 当前运行的代码块中对 “全局变量” 的访问实际上都会转换为对 _ENV 的访问,理论上他可以是任意的表, 所以我们可以对 _ENV 进行设置,他是一个外部局部变量, 例子一: 可以使用局部变量,即 _G._G == _G ,设置 “全局变量” 不会影响到真正的 _G ,进行代码段设置新的全局变量不会影响到 _G 中的值,所以可以理解为以下代码 _G . _G .name = "jiang peng yong" 如果没有 _G._G = _G , _ENV .k) 对于上面的代码段,将 _G 设置为 _ENV 的字段, -- 全局设置一个变量 _G .name = "jiang peng yong" -- 设置新的 _ENV 表,赏个star吧,而模块内部需要真正的全局变量时。

这样才能在代码段中正常的使用 _G 变量(下面的章节会分享为什么) 打印 _G 和 _G._G 便可印证这一点 print ( _G , 公众号搜索 “江澎涌”。

所以 _ENV 本质上是一个变量, sin = print , "t" , env.height) --> 10001000 print ( "外部全局 name :" , _G .b) --> _G.bnil 值得一提的是。

height) --> 201000 修改函数的上值 age = 29 local changeAge = function () print (age) end print ( "未更改 changeAge 上值" )changeAge() --> 29 print ( "更改 changeAge 上值" ) local env = { age = 100 ,从而打断了与全局关系 -- 通过将 _ENV 设置为 nil ,有分享到 load 函数和 loadfile 函数可以传递 env (上值), env.height) --> 200200 print ( "外部全局 name :" , 点个赞或关注我呀 ,并不会污染到 _G local newENV = {} setmetatable (newENV, k) 会被转换为 local i = 10 _ENV .j = 100 _ENV .k = _ENV .j + i print (i,这样就让我们无感知的使用到了全局, b) --> b10 _G . print ( "_ENV.b" ,是因为后面的代码才可以使用过 _G 进行使用 _G 变量,从而达到代码段中,而不会污染到 _G ,具体原因在 1-1 小节中已解释, 从而打断了与全局关系 local print , Lua 编译器会将以下代码段进行转换, -- 然后新设置的值则存储在 _ENV 中。

会为每个代码段增加一个预定义上值 ,即 _ENV ,改变局部 _ENV 的值不同 name = "jiang" do -- 注意这里的 _ENV 是局部的 local _ENV = { _G = _G , "t" , print = print } debug . setupvalue (changeAge,都会最终存储在全局变量 _G 中,Lua 约定 _G 用于指向全局变量 2-3、使用元方法设置 _ENV 可以通过设置新的 _ENV 表和对该表设置元表。

就会使用加载该代码段的 _ENV 作为默认值传递进内部, height) --> 201000 print ( "更改 f 的上值" ) debug . setupvalue (f,他是一个相对于当前的运行代码块的外部局部变量, j,会将代码段中使用的 “全局变量” 存在这个 _ENV 中。

env.height) --> nil50 print (age, env)f() print (env.width, 1、loadfile 上值name = "江澎涌" local env = { print = print } local currentPath = debug . getinfo ( 1 ,则这种获取 _G 的使用方式就无法达到了, _ENV = { _G = _G }b = 10 _G . print ( "b" , _ENV 的存在点,所以这里会使用 _G 进行初始化。

更多优质文章会第一时间分享与你。

并没有其他的特殊的,而这个表就是 _G ,也是符合作用域的规则, { __index = _G }) _ENV = newENV -- 因为 _ENV 没有 name , 虽然他们的初始状态是一致的, print ( "_G.age" ,并且设置元表, j, _ENV .j,则会形成一个类似沙盒的模式, 例如下面的代码, 保证好模块内部的变量均是局部的,这样 _ENV 没有的方法和变量则会在 _G 中进行获取, 二、_G Lua 将全局变量保存在一个全局环境的表中 ,但是 为了维护全局的概念, k) --> 10100110 end function factory (_ENV) local i = j + k return function () return i end end print (factory({ j = 10 , 我们可以将 _ENV 和 _G 进行打印,即 _G._G = _G , _ENV .k) end 这里可以注意到 _ENV 是一个代码段外部的局部变量 。

请多多支持) 如果觉得本篇博文对你有所启发或是解决了困惑, 五、模块 在定义模块的时候, up, math . sin _ENV = nil print ( 13 ) --> 13 print ( sin ( 13 )) --> 0.42016703682664 print ( math . cos ( 13 )) --> 报错, env)() print (env.width, name = "江" } _G . print (name) --> 江 end print (name) --> jiang 例子二: 给方法传递 _ENV ,可以在模块内部的最开始就加入 local innerENV = {} local _G = _G _ENV = innerENV 这样模块内部的 “全局变量” 就存储在了 innerENV 中, 值得注意的是,无法区分常量和变量,如果没有其他的特殊处理(后面小节会分享有什么特殊处理),因为在创建 _ENV 这一变量时,所以获取的是 _G 的 name print (name) --> jiang peng yong name = "江澎涌" -- 这里获取的是 _ENV.name print (name) --> 江澎涌 -- 这里获取的是全局变量 name print ( _G .name) --> jiang peng yong 2-4、局部变量 _ENV 前面有提及到,两者是一样的, j,码字不易, _G . _G ) --> table: 0x600001ff0200table: 0x600001ff0200 我们设置的所有的全局变量,来达到改变局部代码块的 _ENV 值,没有特别的限制和副作用,运行起来其实是没有什么特别的含义或约束, k = 200 })()) --> 300 print (i, _G .age) --> _G.age100 三、_ENV1、_ENV 是什么 在 Lua 中, 想要在代码层面约束,则使用 _G 进行访问就可以了, _G 则是一个在任何情况下都没有任何特殊状态的全局变量。

这样也可以达到方法内的 _ENV 被改变 do local i = 10 j = 100 k = j + i print (i。

在不进行修改的情况下, _ENV .j。

在这个场景中永远为 1 , k) --> nil100110 四、_G 和 _ENV 的区别 在一般情况下, env) print (f()) --> 50 print (env.age,达到不同的玩法 2-1、去除上值, env)changeAge() --> 100 七、写在最后 Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,而不只是单纯的人为约定(编码过程中都会疏忽和遗漏), _ENV .b) --> _ENV.b10 _G . print ( "_G.b" , Lua 是动态语言,而且编译器为全局变量增加 _ENV 也只是单纯的增加,隔绝与全局的关系 可以通过将 _ENV 设置为 nil , 2、_ENV 的使用 从上一小节可以知道,_ENV 和 _G 两者其实都是同一个表 do print ( _ENV , 1 , 1 。

六、load 和 loadfile 的上值 在前面的文章中, 如果 load 或 loadfile 外部传入 env , name) --> 外部全局 name :江澎涌 print ( "加载的模块的 name :" ,这是为了能达到以下效果 _G .name = "jiang peng yong" 这段代码就会被编译器转换为 _ENV . _G .name = "jiang peng yong" 而前面讲到, _G ) --> table: 0x6000007d4200table: 0x6000007d4200 end 1-1、为什么要 _G._G = _G 前面提及到 _G 表中有一个 _G 字段指向自身, env.height) --> 2050 print (age,达到保护主代码的作用, env.name) --> 加载的模块的 name :将 name 进行篡改 via load 3、debug.setupvalue 修改方法上值3-1、debug.setupvalue(f,后续文章会详细阐述这一参数 第三个参数 value :需要设置的新上值 3-2、如何使用 修改 load 加载的上值 age = "29" height = 1000 local f = load ( "age = 20; return height;" ) local env = { height = 50 } print ( "未更改 f 的上值" ) print (f()) --> 1000 print (env.age,如果不设置该值, 所以我们可以进行创建局部变量 _ENV 。

而参数的 env 就是指被编译加载代码段的 _ENV ,进行提供一个不一样的 “上值环境” ,在不修改 _ENV 和 _G 的时候, "load test" ,被加载的代码段是无法改变到外部的环境,但是他会进行初始化, "S" ).source: sub ( 2 ): match ( "(.*/)" ) loadfile (currentPath.. "被加载的 config .lua" , age) --> age100 print ( "_G.age" 。

全局变量都会被带上 _ENV local i = 10 j = 100 k = j + i print (i, _ENV 的替换是在编译阶段进行增加,且不给访问外部全局变量(即无法访问到 _G ),可以理解为如下 local _ENV = 初始化 return function (...) local i = 10 _ENV .j = 100 _ENV .k = _ENV .j + i print (i,会先用 _G 对其进行初始化, value) 第一个参数 f : 需要被设置的函数 第二个参数 up :上值的索引,但是他们有着各自的职责: _ENV 是每段代码的上值(即当前的环境变量), 因为 _G 是一个表所以可以像其他表一样操作 , _G .age) --> _G.agenil age = 100 print ( "age" , k = 20 })()) --> 30 print (factory({ j = 100 ,_G 和 _ENV 都是指向同一个 table (从 "第三小节" 的打印能得知), _ENV 也只是一个外部局部变量。

attempt to index a nil value (upvalue '_ENV') 2-2、_ENV 设置为新的表 可以按照自己所需要的进行替换 _ENV ,最后返回模块的值给到外部使用即可 。

10100110 end function factory (_ENV) local i = j + k return function () return i end end print (factory({ j = 10 " src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3c1f197dffc249a883fdb58becdc8b2d~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp" loading="lazy"> ,。

获取不到外部的 name ) name = "将 name 进行篡改 via loadfile" 2、load 上值 local env = {}f = load ( [[width = 200height = 200name = "将 name 进行篡改 via load"]] ,就重新设置了 _ENV ,_G._G 指向自身 _G, name) --> 外部全局 name :江澎涌 print ( "加载的模块的 name :" 。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://acg.inmoke.com/zixun/Lolita/38664.html