4.1 Assignment
a = "hello" .. "world"
t.n = t.n + 1
multiple assignment, elements separated by commas. For instance, in the assignment
a, b = 10, 2*x
the variable a gets the value 10 and b gets 2*x.
In a multiple assignment, Lua first evaluates all values and only then executes
the assignments. Therefore, we can use a multiple assignment to swap
two values, as in the following examples:
x, y = y, x -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i] -- swap 'a[i]' for 'a[j]'
Lua always adjusts the number of values to the number of variables: when
the list of values is shorter than the list of variables, the extra variables receive
nil as their values; when the list of values is longer, the extra values are silently
discarded:
a, b, c = 0, 1
print(a, b, c) --> 0 1 nil
a, b = a+1, b+1, b+2 -- value of b+2 is ignored
print(a, b) --> 1 2
a, b, c = 0
print(a, b, c) --> 0 nil nil
The last assignment in the above example shows a common mistake. To initialize
a set of variables, you must provide a value for each one:
a, b, c = 0, 0, 0
print(a, b, c) --> 0 0 0 notice this case.
In particular, a multiple assignment is not faster than its equivalent
single assignments. Nevertheless, often we really need multiple assignment. We
already saw an example, to swap two values. A more frequent use is to collect
multiple returns from function calls.
4.2 Local Variables and Blocks
Besides global variables, Lua supports local variables. local statement:
j = 10 -- global variable
local i = 1 -- local variable
Unlike global variables, local variables have their scope limited to the block
where they are declared. A block is the body of a control structure, the body of a
function, or a chunk (the file or string where the variable is declared):
x = 10
local i = 1 -- local to the chunk
while i <= x do
local x = i*2 -- local to the while body
print(x) --> 2, 4, 6, 8, ...
i = i + 1
end
if i > 20 then
local x -- local to the "then" body,出了then 下一个else block 都看不到这个 local x
x = 20
print(x + 2) -- (would print 22 if test succeeded)
else
print(x) --> 10 (the global one)
end
print(x) --> 10 (the global one)
Beware that this example will not work as expected if you enter it in interactive
mode. In interactive mode, each line is a chunk by itself (unless it is not
a complete command). To solve this problem, we can delimit
the whole block explicitly, bracketing it with the keywords do–end. Once you
enter the do, the command completes only at the corresponding end, so Lua
does not execute each line by itself.
These do blocks are useful also when you need finer control over the scope of
some local variables:
do
local a2 = 2*a
local d = (b^2 - 4*a*c)^(1/2)
x1 = (-b + d)/a2
x2 = (-b - d)/a2
end -- scope of 'a2' and 'd' ends here
print(x1, x2)
It is good programming style to use local variables whenever possible. Local
variables help you avoid cluttering the global environment with unnecessary
names. Moreover, the access to local variables is faster than to global ones.
Finally, a local variable vanishes as soon as its scope ends, allowing the garbage
collector to release its value.
local a, b = 1, 10
if a < b then
print(a) --> 1
local a -- '= nil' is implicit
print(a) --> nil
end -- ends the block started at 'then'
print(a, b) --> 1 10
A common idiom in Lua is
local foo = foo
This code creates a local variable, foo, and initializes it with the value of the
global variable foo. (The local foo becomes visible only after its declaration.)
This idiom is useful when the chunk needs to preserve the original value of foo
even if later some other function changes the value of the global foo; it also
speeds up the access to foo.
Because many languages force you to declare all local variables at the beginning
of a block (or a procedure), some people think it is a bad practice to
use declarations in the middle of a block. Quite the opposite: by declaring a
variable only when you need it, you seldom need to declare it without an initial
value (and therefore you seldom forget to initialize it). Moreover, you shorten
the scope of the variable, which increases readability. (印象中C就是这样要用到就要先定义,而不能在中途第一以各新的变量)
4.3 Control Structures
with if for conditional execution and while, repeat, and for for iteration. All control structures
have an explicit terminator:
end terminates if, for and while structures;
until terminates repeat structures.
a,b,r=1,2;
function tesifElse(op)
local a,b,r=4,5,0
if op == "+" then
r = a + b
elseif op == "-" then --注意elseif 是连着写的
r = a - b
elseif op == "*" then
r = a*b
elseif op == "/" then
r = a/b
else
error("invalid operation")
end
print(r);
end
tesifElse("+");
print(r);
--while
local i = 1
while a[i] do
print(a[i])
i = i + 1
end
-- print the first non-empty input line
repeat
line = io.read()
until line ~= ""
print(line)
Unlike in most other languages, in Lua the scope of a local variable declared
inside the loop includes the condition:
local sqr = x/2
repeat
sqr = (sqr + x/sqr)/2
local error = math.abs(sqr^2 - x)
until error < x/10000 -- local 'error' still visible here
Numeric for
The for statement has two variants: the numeric for and the generic for.A numeric for has the following syntax:
for var = exp1, exp2, exp3 do
<something>
end
This loop will execute something for each value of var from exp1 to exp2, using
exp3 as the step to increment var. This third expression is optional; when
absent, Lua assumes 1 as the step value. As typical examples of such loops,
we have
for i = 1, f(x) do print(i) end
for i = 10, 1, -1 do print(i) end
for i = 1, math.huge do
if (0.3*i^3 - 20*i^2 - 500 >= 0) then
print(i)
break
end
end
The for loop has some subtleties that you should learn in order to make good
use of it. First, all three expressions are evaluated once, before the loop starts.
For instance, in our first example, Lua calls f(x) only once. Second, the control
variable is a local variable automatically declared by the for statement, and it
is visible only inside the loop. A typical mistake is to assume that the variable
still exists after the loop ends:
-- find a value in a list
local found = nil
for i = 1, #a do
if a[i] < 0 then
found = i -- save value of 'i'
break
end
end
print(found)
Generic for
The generic for loop traverses all values returned by an iterator function:
-- print all values of table 't'
for k, v in pairs(t) do
print(k, v)
end
This example uses pairs, a handy iterator function to traverse a table provided
by the basic Lua library> For each step in that loop, k gets a key, while v gets
the value associated with this key.
tttt={
["treovr"]="trevor yang", -- key can't be write as "treovr", if you want to write double quote, add double squre bracket
cybar="cybar Lv",
jerico="jerico zhao",
"abc",
"efg",
"hijk",
};
for k,v in pairs(tttt) do
print(k,v);
end
cybar cybar Lv
jerico jerico zhao
treovr trevor yang
sequence value will also print too
The standard libraries provide several iterators, which allow us to iterate over the lines of a
file (io.lines), the pairs of a table (pairs), the entries of a sequence (ipairs),
the words of a string (string.gmatch), and so on.
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
revDays = {["Sunday"] = 1, ["Monday"] = 2,
["Tuesday"] = 3, ["Wednesday"] = 4,
["Thursday"] = 5, ["Friday"] = 6,
["Saturday"] = 7}--construct by for
revDays = {}
for k,v in pairs(days) do
revDays[v] = k
end
4.4 break, return, and goto
A return statement returns occasional results from a function or simply
finishes the function. There is an implicit return at the end of any function, so
you do not need to write one if your function ends naturally, without returning
any value.
For syntactic reasons, a return can appear only as the last statement of a
block: in other words, as the last statement in your chunk or just before an
end, an else, or an until. For instance, in the next example, return is the last
statement of the then block.
local i = 1
while a[i] do
if a[i] == v then return i end
i = i + 1
end
Usually, these are the places where we use a return, because any other statement
following it would be unreachable. Sometimes, however, it may be useful
to write a return in the middle of a block; for instance, you may be debugging a
function and want to avoid its execution. In such cases, you can use an explicit
do block around the statement:
function foo ()
return --<< SYNTAX ERROR
-- 'return' is the last statement in the next block
do return end -- OK,new a new explicit do block. to meet that the return before the end
<other statements>
end
Lua poses some restrictions to where you can jump with a goto. First, labels follow the usual visibility rules, so you cannot jump into a block (because a label inside a block is not visible outside it).
Second, you cannot jump out of a function. (Note that the first rule already excludes the possibility of jumping
into a function.)
Third, you cannot jump into the scope of a local variable.
Notic that goto 是连在一起写的
while some_condition do
::redo:: --::lableName::
if some_other_condition then goto continue
elseif yet_another_condition then goto redo
end
<some code>
::continue::
end
A useful detail in the specification of Lua is that the scope of a local variable
ends on the last non-void statement of the block where the variable is defined;
labels are considered void statements. To see the usefulness of this detail,
consider the next fragment: ---have not idea still
while some_condition do
if some_other_condition then goto continue end
local var = something
<some code>
::continue::
end
Listing 4.1. An example of a state machine with goto:
::s1:: do
local c = io.read(1)
if c == '0' then goto s2
elseif c == nil then print'ok'; return
else goto s1
end
end
::s2:: do
local c = io.read(1)
if c == '0' then goto s1
elseif c == nil then print'not ok'; return
else goto s2
end
end
goto s1
the game has several special situations in each room, then this state-machine
design is quite appropriate.
Exercise 4.1: Most languages with a C-like syntax do not offer an elseif
construct. Why does Lua need this construct more than those languages?
if provide else if , then when Lua parse else will treat it else???
Page57 continue the exercise.
--[[
-- still have problem for this goto
::s1:: do
print("going to s1...");
local c=io.read(1);
if c=="1" then goto s2;
elseif c=="0" then print "will end the s1";
else
print "else back to s1";
goto s1;
end;
end;
::s2:: do
print("go into s2");
local c=io.read(1);
if c=="3" then goto s1;
elseif c=="4" then print "will end s2";
else
goto s2;
end;
end
--]]