Lua中的变量,如果没有local关键字,全都是全局变量,Lua也是用Table来管理全局变量的,Lua把这些全局变量放在了一个叫“_G”的Table里。
> a = 1
> print(a)
1
> _G["a"]
1
> a = 2
> _G["a"]
2
打印出全局变量_G中的所有东西:
for n in pairs(_G) do
print(n)
end
读书笔记: Programming in Lua, 4th Edition.
do-end 就像是一个花括号,用来构成一个作用域。
> local x1
> do
>> local x1 = 1
>> print(x1)
>> end
1
> print(x1)
nil
if op == "+" then
r = a + b
elseif op == "-" then
r = a - b
elseif op == "*" then
r = a * b
elseif op == "/" then
r = a / b
else
error("invalid operation")
end
local i = 1
while a[i] do
print(a[i])
i = i + 1
end
至少执行一次,就是C语言中的do-while
-- print the first non-empty input line
local line
repeat
line = io.read()
until line ~= ""
print(line)
Differently from most other languages, in Lua the scope of a local variable declared inside the loop includes the condition:
-- computes the square root of 'x' using Newton-Raphson method
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
The for statement has two variants: the numerical for and the generic for.
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 one as the step value.
for var = exp1, exp2, exp3 do
something
end
If we want a loop without an upper limit, we can use the constant math.huge:
for i = 1, math.huge do
if (0.3*i^3 - 20*i^2 - 500 >= 0) then
print(i)
break
end
end
Creates a new coroutine, with body f. f must be a function. Returns this new coroutine, an object with type “thread”.
创建一个新的协程。f必须是一个函数。返回值是这个新的协程,返回值的类型是thread。
Returns true when the running coroutine can yield.
A running coroutine is yieldable if it is not the main thread and it is not inside a non-yieldable C function.
返回true当正在运行的协程可以被yield。
Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, … are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, … are passed as the results from the yield.
If the coroutine runs without any errors, resume returns true plus any values passed to yield (when the coroutine yields) or any values returned by the body function (when the coroutine terminates). If there is any error, resume returns false plus the error message.
Returns the running coroutine plus a boolean, true when the running coroutine is the main one.
返回一个正在运行的协程和一个boolean值,这个协程是主线程的话boolean值为true。
Returns the status of coroutine co, as a string: “running”, if the coroutine is running (that is, it called status); “suspended”, if the coroutine is suspended in a call to yield, or if it has not started running yet; “normal” if the coroutine is active but not running (that is, it has resumed another coroutine); and “dead” if the coroutine has finished its body function, or if it has stopped with an error.
Creates a new coroutine, with body f. f must be a function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.
Suspends the execution of the calling coroutine. Any arguments to yield are passed as extra results to resume.
挂起调用这个函数的协程。参数会传递给resume,作为resume的返回值。
co = coroutine.create(
function(i)
print(i);
end
)
print(coroutine.status( co ))
coroutine.resume(co, 1)
print(coroutine.status( co ))
print("---------------")
co = coroutine.wrap(
function(i)
print(i);
end
)
co(2)
print("---------------")
co2 = coroutine.create(
function()
for i = 1, 10 do
print(i)
if i == 3 then
print(coroutine.status(co2))
print(coroutine.running( ))
end
coroutine.yield()
end
end
)
coroutine.resume(co2)
coroutine.resume(co2)
coroutine.resume(co2)
print(coroutine.status(co2))
print(coroutine.running( ))
输出:
suspended
1
dead
---------------
2
---------------
1
2
3
running
thread: 0000000000459dd8 false
suspended
thread: 0000000000456638 true
function foo(a)
print("foo a = ", a)
return coroutine.yield(2 * a)
end
co = coroutine.create(
function(a, b)
print("1==== ", a, b)
local r = foo( a + 1 )
print("2==== ", r)
local r, s = coroutine.yield(a + b, a - b)
print("3==== ", r, s)
return b, "end of coroutine."
end
)
print("main", coroutine.resume(co, 1, 10))
print("--------------")
print("main", coroutine.resume(co, "abc"))
print("--------------")
print("main", coroutine.resume(co, "xxx", "yyy"))
print("--------------")
print("main", coroutine.resume(co, "xxx", "yyy"))
print("--------------")
输出:
1==== 1 10
foo a = 2
main true 4
--------------
2==== abc
main true 11 -9
--------------
3==== xxx yyy
main true 10 end of coroutine.
--------------
main false cannot resume dead coroutine
--------------
local newProductor
function productor()
local i = 0
while true do
i = i + 1
if i > 10 then
break;
end
send(i)
end
end
function consumer()
while true do
local s, i = receive()
if s == false then
break;
end
print(i)
end
end
function receive()
local status, value = coroutine.resume(newProductor)
return status, value
end
function send(x)
coroutine.yield(x)
end
newProductor = coroutine.create( productor )
consumer()
输出:
1
2
3
4
5
6
7
8
9
10
nil
读书笔记: Programming in Lua, 4th Edition.
> a = {}
> a["x"] = 10
> b = a -- 'b' refers to the same table as 'a'
> b["x"] --> 10
> b["x"] = 20
> a["x"] --> 20
> a = nil -- only 'b' still refers to the table
> b = nil -- no references left to the table
When a program has no more references to a table, the garbage collector will eventually delete the table and reuse its memory.
> a = {} -- empty table
> a.x = 10 -- same as a["x"] = 10
> a.x --> 10 -- same as a["x"]
> a.y --> nil -- same as a["y"]
A common mistake for beginners is to confuse a.x with a[x]. The first form represents a[“x”], that is, a table indexed by the string “x”. The second form is a table indexed by the value of the variable x. See the difference:
> a = {}
> x = "y"
> a[x] = 10 -- put 10 in field "y"
> a[x] --> 10 -- value of field "y"
> a.x --> nil -- value of field "x" (undefined)
> a.y --> 10 -- value of field "y"
> i = 10; j = "10"; k = "+10"
> a = {}
> a[i] = "number key"
> a[j] = "string key"
> a[k] = "another string key"
> a[i] --> number key
> a[j] --> string key
> a[k] --> another string key
> a[tonumber(j)] --> number key
> a[tonumber(k)] --> number key
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
print(days[4]) --> Wednesday
opnames = {["+"] = "add", ["-"] = "sub",
["*"] = "mul", ["/"] = "div"}
i = 20; s = "-"
a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
print(opnames[s]) --> sub
print(a[22]) --> ---
{x = 0, y = 0} <--> {["x"] = 0, ["y"] = 0}
{"r", "g", "b"} <--> {[1] = "r", [2] = "g", [3] = "b"}
To represent a conventional array or a list, we simply use a table with integer keys.
We call such a list without holes a sequence.
We can traverse all key–value pairs in a table with the pairs iterator:
t = {10, print, x = 12, k = "hi"}
for k, v in pairs(t) do
print(k, v)
end
--> 1 10
--> k hi
--> 2 function: 0x420610
--> x 12
For lists, we can use the ipairs iterator:
t = {10, print, 12, "hi"}
for k, v in ipairs(t) do
print(k, v)
end
--> 1 10
--> 2 function: 0x420610
--> 3 12
--> 4 hi
In this case, Lua trivially ensures the order.
Another way to traverse a sequence is with a numerical for:
t = {10, print, 12, "hi"}
for k = 1, #t do
print(k, t[k])
end
--> 1 10
--> 2 function: 0x420610
--> 3 12
--> 4 hi
读书笔记: Programming in Lua, 4th Edition.
> a = "one string"
> b = string.gsub(a, "one", "another")
> print(a, b)
one string another string
>
> a = "hello"
> print(#a)
5
> print(#"good bye")
8
> "Hello " .. "World"
Hello World
> "result is " .. 3
result is 3
> a = "Hello"
> a .. " World"
Hello World
a = "a line"
b = 'another line'
They are equivalent; the only difference is that inside each kind of quote we can use the other quote without escapes.
> page = [[
>> <html>
>> <head>
>> <title>An HTML Page</title>
>> </head>
>> <body>
>> <a href="http://www.lua.org">Lua</a>
>> </body>
>> </html>
>> ]]
> print(page)
<html>
<head>
<title>An HTML Page</title>
</head>
<body>
<a href="http://www.lua.org">Lua</a>
</body>
</html>
> print(10 .. 20)
1020
> "10" + 1
11.0
> tonumber(" -3 ")
-3
> tonumber(" 10e4 ")
100000.0
> tonumber("10e")
nil
By default, tonumber assumes decimal notation, but we can specify any base between 2 and 36 for the conversion
> tonumber("100101", 2)
37
> tonumber("fff", 16)
4095
> tonumber("-ZZ", 36)
-1295
> tonumber("987", 8)
nil
> print(tostring(10) == "10")
true
> string.len("abc")
3
> string.rep("abc", 3)
abcabcabc
> string.reverse("A Long Line!")
!eniL gnoL A
> string.lower("A Long Line!")
a long line!
> string.upper("A Long Line!")
A LONG LINE!
As a typical use, if we want to compare two strings regardless of case, we can write something like this:
string.lower(a) < string.lower(b)
The call string.sub(s, i, j) extracts a piece of the string s, from the i-th to the j-th character inclusive. (The first character of a string has index 1.) We can also use negative indices, which count from the end of the string: index -1 refers to the last character, -2 to the previous one, and so on. Therefore, the call string.sub(s, 1, j) gets a prefix of the string s with length j; string.sub(s, j, -1) gets a suffix of the string, starting at the j-th character; and string.sub(s, 2, -2) returns a copy of the string s with the first and last characters removed:
> s = "[in brackets]"
> string.sub(s, 2, -2)
in brackets
> string.sub(s, 1, 3)
[in
> string.sub(s, -1, -1)
]
> string.sub(s, -2, -1)
s]
> print(s)
[in brackets]
> s = string.sub(s, 2, -2)
> print(s)
in brackets
> print(string.char(97))
a
> i = 99; print(string.char(i, i+1, i+2))
cde
> print(string.byte("abc"))
97
> print(string.byte("abc", 2))
98
> print(string.byte("abc", -1))
99
A call like string.byte(s, i, j) returns multiple values with the numeric representation of all characters between indices i and j (inclusive):
> print(string.byte("abc", 1, 2))
97 98
A nice idiom is {string.byte(s, 1, -1)}, which creates a list with the codes of all characters in s.
和C语言的printf是一样的。
> string.format("x = %d y = %d", 10, 20)
x = 10 y = 20
> string.format("x = %x", 200)
x = c8
> string.format("x = 0x%X", 200)
x = 0xC8
> string.format("x = %f", 200)
x = 200.000000
> tag, title = "h1", "a title"
> string.format("<%s>%s<%s>", tag, title, tag)
<h1>a title<h1>
> print(string.format("pi = %.4f", math.pi))
pi = 3.1416
> d = 5; m = 11; y = 1990
> print(string.format("%02d/%02d/%04d", d, m, y))
05/11/1990
> string.find("hello world", "wor")
7 9
> string.find("hello world", "war")
nil
> string.gsub("hello world", "l", ".")
he..o wor.d 3
> string.gsub("hello world", "ll", "..")
he..o world 1
> string.gsub("hello world", "a", ".")
hello world 0
读书笔记: Programming in Lua, 4th Edition.
print(8*9, 9/8)
a = math.sin(3) + math.cos(10)
print(os.date())
-- add the elements of sequence 'a'
function add (a)
local sum = 0
for i = 1, #a do
sum = sum + a[i]
end
return sum
end
if the function has one single argument and that argument is either a literal string or a table constructor, then the parentheses are optional:
如果函数只有一个参数,并且这个参数是字符串或者是table的话,函数的括号()可以省略。
print "Hello World" <--> print("Hello World")
dofile 'a.lua' <--> dofile ('a.lua')
print [[a multi-line <--> print([[a multi-line
message]] message]])
f{x=10, y=20} <--> f({x=10, y=20})
type{} <--> type({})
We can call a function with a number of arguments different from its number of parameters. Lua adjusts the number of arguments to the number of parameters by throwing away extra arguments and supplying nils to extra parameters. For instance, consider the next function:
函数调用时提供的参数可以和函数定义时的参数个数不同。不足的用nil补全,多余的话会被自动忽略。
function f (a, b)
print(a, b)
end
f() --> nil nil
f(3) --> 3 nil
f(3, 4) --> 3 4
f(3, 4, 5) --> 3 4 (5 is discarded)
function incCount (n)
n = n or 1
globalCounter = globalCounter + n
end
function maximum (a)
local mi = 1 -- index of the maximum value
local m = a[mi] -- maximum value
for i = 1, #a do
if a[i] > m then
mi = i; m = a[i]
end
end
return m, mi -- return the maximum and its index
end
print(maximum({8,10,23,12,5})) --> 23 3
Lua always adjusts the number of results from a function to the circumstances of the call.
When we call a function as a statement, Lua discards all results from the function.
When we use a call as an expression (e.g., the operand of an addition), Lua keeps only the first result.
We get all results only when the call is the last (or the only) expression in a list of expressions.
function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a", "b" end -- returns 2 results
x, y = foo2() -- x="a", y="b"
x = foo2() -- x="a", "b" is discarded
x, y, z = 10, foo2() -- x=10, y="a", z="b"
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x="a", y=nil
x,y,z = foo2() -- x="a", y="b", z=nil
Remember that multiple results only happen when the call is the last (or only) expression in a list. A function call that is not the last element in the list always produces exactly one result:
x,y = foo2(), 20 -- x="a", y=20 ('b' discarded)
x,y = foo0(), 20, 30 -- x=nil, y=20 (30 is discarded)
print(foo0()) --> (no results)
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (see next)
A constructor also collects all results from a call, without any adjustments:
t = {foo0()} -- t = {} (an empty table)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"}
As always, this behavior happens only when the call is the last expression in the list; calls in any other position produce exactly one result:
t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4
We can force a call to return exactly one result by enclosing it in an extra pair of parentheses:
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a
function add(...)
local s = 0
for _, v in ipairs{...} do
s = s + v
end
return s
end
print(add(3, 4, 10, 25, 12)) --> 54
Lua offers the function table.pack.1 This function receives any number of arguments and returns a new table with all its arguments (just like {…}), but this table has also an extra field “n”, with the total number of arguments.
function nonils(...)
local arg = table.pack(...)
for i = 1, arg.n do
if arg[i] == nil then
return false
end
end
return true
end
print(nonils(2,3,nil)) --> false
print(nonils(2,3)) --> true
print(nonils()) --> true
print(nonils(nil)) --> false
A call to select has always one fixed argument, the selector, plus a variable number of extra arguments. If the selector is a number n, select returns all arguments after the n-th argument; otherwise, the selector should be the string “#”, so that select returns the total number of extra arguments.
print(select(1, "a", "b", "c")) --> a b c
print(select(2, "a", "b", "c")) --> b c
print(select(3, "a", "b", "c")) --> c
print(select("#", "a", "b", "c")) --> 3
function add (...)
local s = 0
for i = 1, select("#", ...) do
s = s + select(i, ...)
end
return s
end
A special function with multiple returns is table.unpack. It takes a list and returns as results all elements from the list:
print(table.unpack{10,20,30}) --> 10 20 30
a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded
As the name implies, table.unpack is the reverse of table.pack. While pack transforms a parameter list into a real Lua list (a table), unpack transforms a real Lua list (a table) into a return list, which can be given as the parameter list to another function.
function unpack (t, i, n)
i = i or 1
n = n or #t
if i <= n then
return t[i], unpack(t, i + 1, n)
end
end
尾调用:也就是在一个函数A的最后调用一个函数B,因为函数A已经执行完了,所以函数B可以重复利用A的栈空间,提高效率。