Programming in Lua, 2Nd Edition - Chapter 14: The Environment

本文介绍了Lua语言中全局变量的管理方式,包括如何通过环境表存储全局变量、使用动态名称的全局变量及如何声明全局变量等内容,并探讨了如何利用Lua的特性定制全局变量的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

 

Chapter 14: The Environment

 

Lua 把所有全局变量都存在一个普通的表environment 里面。(更准确的说,是多个环境)这样做的好外是简化了lua 的内部实现。environment 本身又存在_G 里面。

 

打印当前已定义的所有全局变量

 

for n in pairs(_G) do print(n) end

 

 

14.1 Global Variables with Dynamic Names

 

function getfield (f)

       local v = _G -- start with the table of globals

       for w in string.gmatch(f, "[%w_]+") do

              v = v[w]

       end

       return v

end

 

function setfield (f, v)

       local t = _G -- start with the table of globals

       for w, d in string.gmatch(f, "([%w_]+)(.?)") do

              if d == "." then -- not last field?

                     t[w] = t[w] or {} -- create table if absent

                     t = t[w] -- get the table

              else -- last field

                     t[w] = v -- do the assignment

              end

       end

end

 

setfield("t.x.y", 10)   -- creates a global table t, another table t.x, and assigns 10 to t.x.y

print(t.x.y) --> 10

print(getfield("t.x.y")) --> 10

 


 

14.2 Global-Variable Declarations

 

全局变量无需声明。虽然这对小程序提供了便利,但大程序中易引起难以找出的错误。可以改变这一行为,如果我们愿意。因为Lua 将全局变量存在一个普通的表里面,当访问全局变量的时侯,我们可以使用元表改变它的行为。

 

检测以不存在的key访问全局表

 

setmetatable(_G, {

       __newindex = function (_, n)

              error("attempt to write to undeclared variable " .. n, 2)

         end,

       __index = function (_, n)

              error("attempt to read undeclared variable " .. n, 2)

         end,

})

 

print(a) -- stdin:1: attempt to read undeclared variable a

 

但是,我们如何声明新变量?一种方法是使用rawset ,它会忽略元方法:

 

不允许未经声明就使用全局变量

 

function declare (name, initval)

       rawset(_G, name, initval or false)

end

 

setmetatable(_G, {

       __newindex = function (_, n)

              error("attempt to write to undeclared variable " .. n, 2)

         end,

       __index = function (_, n)

              error("attempt to read undeclared variable " .. n, 2)

         end,

})

 

a=1  -- stdin:1: attempt to read undeclared variable a

declare "a"

a=1  -- OK

print(a)

 


 

只允许在main chunk 中定义全局变量

 

function declare (name, initval)

       rawset(_G, name, initval or false)

end

 

setmetatable(_G, {

       __newindex = function (t, n, v)

              local w = debug.getinfo(2, "S").what

              if w ~= "main" and w ~= "C" then

                     error("attempt to write to undeclared variable " .. n, 2)

              end

              rawset(t, n, v)

         end,

       __index = function (_, n)

              error("attempt to read undeclared variable " .. n, 2)

         end,

})

 

a=1 -- OK

print(a)

 

检测一个变量是否存在,我们不能简单的与nil 比较,而是使用rawget

 

if rawget(_G, var) == nil then

-- 'var' is undeclared

...

end

 

 

14.3 Non-Global Environments

 

Lua 允许每个函数有自已的环境。使用setfenv (set function environment) 改变函数环境。

 

a = 1 -- create a global variable

-- change current environment to a new empty table

setfenv(1, {})

print(a)

-------------------------------------------

a = 1 -- create a global variable

setfenv(1, {g = _G}) -- change current environment

g.print(a) --> nil

g.print(g.a) --> 1

--------------------

a = 1

local newgt = {} -- create new environment

setmetatable(newgt, {__index = _G})

setfenv(1, newgt) -- set it

print(a) --> 1

a = 10

print(a) --> 10

print(_G.a) --> 1

_G.a = 20

print(_G.a) --> 20

-------------------------

function factory ()

       return function ()

              return a -- "global" a

       end

end

 

a = 3

f1 = factory()

f2 = factory()

print(f1()) --> 3

print(f2()) --> 3

setfenv(f1, {a = 10})

print(f1()) --> 10

print(f2()) --> 3

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值