This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
Programming in Lua | ||
Part II. Tables and Objects Chapter 14. The Environment |
Usually, assignment is enough for getting and setting global variables. However, often we need some form of meta-programming, such as when we need to manipulate a global variable whose name is stored in another variable, or somehow computed at run time. To get the value of this variable, many programmers are tempted to write something like
loadstring("value = " .. varname)()or
value = loadstring("return " .. varname)()If
varname
is x
, for instance,
the concatenation will result in "return x"
(or "value = x"
, with the first form),
which when run achieves the desired result.
However, such codes involve the creation and compilation of a new chunk
and lots of extra work.
You can accomplish the same effect with the following code,
which is more than an order of magnitude more efficient
than the previous one:
value = _G[varname]Because the environment is a regular table, you can simply index it with the desired key (the variable name).
In a similar way,
you can assign to a global variable whose name is computed dynamically,
writing _G[varname] = value
.
Beware, however:
Some programmers get a little excited with these functions
and end up writing code like
_G["a"] = _G["var1"]
,
which is just a complicated way to write a = var1
.
A generalization of the previous problem
is to allow fields in a dynamic name,
such as "io.read"
or "a.b.c.d"
.
We solve this problem with a loop,
which starts at _G
and evolves field by field:
function getfield (f) local v = _G -- start with the table of globals for w in string.gfind(f, "[%w_]+") do v = v[w] end return v endWe rely on
gfind
, from the string
library,
to iterate over all words in f
(where "word" is a sequence of one or more
alphanumeric characters and underscores).
The corresponding function to set fields is a little more complex. An assignment like
a.b.c.d.e = vis exactly equivalent to
local temp = a.b.c.d temp.e = vThat is, we must retrieve up to the last name; we must handle the last field separately. The new
setfield
function also creates intermediate tables
in a path when they do not exist:
function setfield (f, v) local t = _G -- start with the table of globals for w, d in string.gfind(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 endThis new pattern captures the field name in variable
w
and an optional following dot in variable d
.
If a field name is not followed by a dot then it is the last name.
(We will discuss pattern matching at great length
in Chapter 20.)
With the previous functions, the call
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
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |