start
运行lua程序的方式:
lua的交互模式:
1
2print("Hello World")
Hello Worldlua+文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16ksance0@ubuntu:~/lua/workspace$ lua func.lua
enter a num
3
6
-- defines a factorial function //comment
function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end
print("enter a number:")
a = io.read("*number") -- read a number
print(fact(a))
chunk概念:
- Each piece of code that Lua executes, such as a file or a single line in interactive mode, is a chunk. More specifically, a chunk is simply a sequence of statements.
所以一次输入:文件或者交互模式下的语句都是一个chunk;1
2
3
4
5
6
7
8
9
10
11下面四个是相同的chunk:
a = 1
b = a*2
a = 1;
b = a*2;
a = 1 ; b = a*2
a = 1 b = a*2 -- ugly, but valid
同一行可以用;隔开
退出交互模式,在加载lua文件运行:
退出交互模式:just type end-of-file (ctrl-D in Unix, ctrl-Z in DOS/Windows), or call the exit function, from the Operating System library (you have to type os.exit()
). 在下加载:
1
2
3
4
5
6
7
8
9
10
11a.lua: x=1
b.lua: print(x)
ksance0@ubuntu:~/lua/workspace$ lua -la -lb
1
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio
>
加-i参数时:
ksance0@ubuntu:~/lua/workspace$ lua -i -la -lb
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio
1
>交互模式下加载:
1
2
3
4
5
6
7
8
9
10
11
12
13
14-- file 'lib1.lua'
function norm (x, y)
local n2 = x^2 + y^2
return math.sqrt(n2)
end
function twice (x)
return 2*x
end
Then, in interactive mode, you can type
> dofile("lib1.lua") -- load your library
> n = norm(3.4, 1.0)
> print(twice(n)) --> 7.0880180586677全局变量
全局变量是不需要先声明的变量,它初值为nil:
1
2
3print(b) --> nil
b = 10
print(b) --> 10当想删除一个全局变量:b=nil
一个全局变量存在当且仅当它不为空一些词法约定
标识符可以是字符,下划线和数字,但是不能以数字开头:建议不用下划线开头,避免冲突
保留字:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until
whilelua大小写敏感
如何注释:
1
-- eg: --a=10
注释多行:
1
2
3
4
5
6
7--[[
print(10) -- no action (comment)
--]]
错误用法:
---[[
print(10) -- no action (comment)
--]]lua解释器介绍:
lua解释器也叫lua.c,因为是由lua.c执行: /usr/local/bin/lua
脚本开头指定解释器:
1
2
3
4
5#!/usr/local/bin/lua 或#!/usr/bin/env lua指定lua解释器后,不用lua filename.lua执行,即直接./xxx.lua
否则: lua [options] [script [args]]
那么这里options有哪些呢?
1)-e 允许直接运行: prompt> lua -e "print(math.sin(12))" --> -0.53657291800043
2) -i允许加载文件到lua交互模式运行: prompt> lua -i -l a.lua -e "x = 10"改变lua交互模式表示:
1
2
3
4ksance0@ubuntu:~/lua/workspace$ lua -i -e "_PROMPT='lua32> '"
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio
lua32>
//这个_PROMPT是一个内定全局变量lua和它的输入参数:
1
2
3
4
5
6
7
8lua -e "sin=math.sin" script a b
lua collects the arguments as follows:
arg[-3] = "lua"
arg[-2] = "-e"
arg[-1] = "sin=math.sin"
arg[0] = "script"
arg[1] = "a"
arg[2] = "b"更多:
在开始运行参数之前,lua会查找一个名为LUA_INIT的环境变量。如果有这样一个变量,并且它的内容是@filename,那么lua加载给定的文件。如果定义了LUA_INIT但没有以’ @开始,那么lua会假设它包含lua代码并运行它。在配置独立解释器时,这个变量提供了强大的功能,因为您在配置中使用了Lua的全部功能。您可以预加载包、更改提示符和路径、定义自己的函数、重命名或删除函数,等等。
type_value:
8种类型
1 |
|
值可以是任意类型:
1 | print(type(a)) --> nil (`a' is not initialized) |
Nil类型:
Nil是一个单值类型,只有一个值nil,它是global 变量的默认值,也可以用来赋值以删除全局变量,它表示non-value
Booleans:
包括true和false两个取值,条件语句中false和nil为false,其他为true;
注意:不像其他脚本语言:lua中,0和空字符串表示为true;
Number:
lua中数字类型只有double和float,lua没有整型数,因为它不需要;
以下是有效的数字常量:4 0.4 4.57e-3 0.3e12 5e+20
注意lua用double和float并不比整数效率差;
String
和C一样是一串字符,8位每个,不可变,可赋值;
string在lua中时自动内存管理的对象,和其他lua对象一样;
lua可以处理很长的字符串:Programs that manipulate strings with 100K or 1M characters are not unusual in Lua.
可以用单引号或双引号: a=’a linx’ / a=”line”
可以和C一样用转义字符;“alo\n123\”和“\97lo\10\04923”具有相同的值:97是a的ASCII代码,10是换行代码
可以用[[….]]来分隔文本字符串;
连接字符串:
1
2
3
4
5
6
7print("10" + 1) --> 11
print("10 + 1") --> 10 + 1
print("-5.3e-10"*"2") --> -1.06e-09
print("hello" + 1) -- ERROR (cannot convert "hello")
print(10 .. 20) --> 1020
print(tostring(10) == "10") --> true
print(10 .. "" == "10") --> truetable
关联数组:key可以是除nil之外的任何类型,无固定长度,动态增长;当我们用io.read时,可以说是读read为key的一个table,在io package中;
table是对象,通过构造表达式可以构造一个table:
1
2
3
4
5
6
7
8
9a = {} -- create a table and store its reference in `a'
k = "x"
a[k] = 10 -- new entry, with key="x" and value=10
a[20] = "great" -- new entry, with key=20 and value="great"
print(a["x"]) --> 10
k = 20
print(a[k]) --> "great"
a["x"] = a["x"] + 1 -- increments entry "x"
print(a["x"]) --> 11保存表的变量和表本身无关:直到最后一个引用删除,表才被删除和释放内存
1
2
3
4
5
6
7
8a = {}
a["x"] = 10
b = a -- `b' refers to the same table as `a'
print(b["x"]) --> 10
b["x"] = 20
print(a["x"]) --> 20
a = nil -- now only `b' still refers to the table
b = nil -- now there are no references left to the table表可以容纳多种类型的值:
1
2
3
4
5
6
7a = {} -- empty table
-- create 1000 new entries
for i=1,1000 do a[i] = i*2 end
print(a[9]) --> 18
a["x"] = 10
print(a["x"]) --> 10
print(a["y"]) --> nil 值未被初始化时,为nil,和全局变量一样注意索引类型的不同
function:
像python一样,lua中的函数也可以像变量一样传递,或者说他就是变量;lua也可以调用C函数
Userdata and Threads:TODO
expressions:
四则运算:+-*/ -(负),乘方^
关系运算符: < > <= >= == ~=,lua根据类型比较,结果为false or true, nil只会等于它本身
1 | lua比较tables, userdata, and functions by reference,所以这里必须是指向同个object才相等 |
逻辑运算符:and or not,三目运算符: a ? b : c
1 | print(not nil) --> true |
连接符:..
1 | print("Hello " .. "World") --> Hello World |
符号优先级:
1 | ^ |
table构造器:
1 | 1) {} eg:a={} |
语句Statements:
赋值
1 | a="hel".."low" |
多重赋值:
1
2
3
4
5
6lua32> t,e=3,4
lua32> print(t..e)
34
利用多重赋值交换值:
x, y = y, x -- swap `x' for `y'
a[i], a[j] = a[j], a[i] -- swap `a[i]' for `a[j]'不足补nil,太多参数则丢弃
1
2
3
4
5
6a, 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使用函数返回的参数:
1
2
3
4
5
6
7
8function f()
> return 1,2
> end
a,b=f()
print(a);print(b)
1
2
本地变量和块
- 本地变量定义
1
2j = 10 -- global variable
local i = 1 -- local variable - 本地变量作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20chunk, function,流程控制块
eg:xxx.lua: 交互模式下不生效;
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
x = 20
print(x + 2)
else
print(x) --> 10 (the global one)
end
print(x) --> 10 (the global one) - 交互模式下:
1
2
3
4
5lua32> local yy=3
lua32> print(yy)
nil
lua32>
从上面例子看到,下一行就是新的chunk,所以yy作用域只在那一行; - 用法举例:
1
2
3
4
5
6
7local 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 - 强制指定作用域:
1
2
3
4
5
6
7do
local a2 = 2*a
local d = sqrt(b^2 - 4*a*c)
x1 = (-b + d)/a2
x2 = (-b - d)/a2
a2' and `d' ends here -- scope of `
print(x1, x2)控制流程:
- 简介:有if,while,repeat,for,end,until
- if语句:
1
2
3
4
5
6
7
8
9
10
11if 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 - while:
1
2
3
4
5local i = 1
while a[i] do
print(a[i])
i = i + 1
end - repeat:执行至少一次,直到条件不满足:
1
2
3
4
5-- print the first non-empty line
repeat
line = io.read()
until line ~= ""
print(line) - for:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19基本语法:
for var=exp1,exp2,exp3 do
something
end
参数:exp1,exp2 范围,如1,10 /10,1
exp3:可选 ,表示递增或递减的步长,eg: 1,10,2 则循环:1,3,5,7,9,无指定则默认为1;
for i=1,f(x) do print(i) end
for i=10,1,1 do print(i) end; 无结果
for i=10,1,0 do print(i) end; 死循环
注意i这里是本地变量,若需使用如下:可以使用break退出循环
-- find a value in a list
local found = nil
for i=1,a.n do
if a[i] == value then
found = i -- save value of `i'
break
end
end
print(found) - for 2:遍历结构中的所有值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23-- print all values of array `a'
for i,v in ipairs(a) do print(v) end
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
lua32> for i,v in ipairs(days) do
revDays[v] = i
print(revDays[v]);print(v)
end
1
Sunday
2
Monday
3
Tuesday
4
Wednesday
5
Thursday
6
Friday
7
Saturday
lua32> - break,return ;
function:
函数基本格式:
1 | -- add all elements of array `a' |
函数可以返回多个参数:
1 | function foo0 () end -- returns no results |
函数的可选参数:
1 | function g (a, b, ...) end |
#####函数位置参数:
1 | lua不提供位置参数的功能,但是可以通过传递table来间接指定对应参数: |
高级函数
- 函数作为值传递:
1
2
3
4
5
6a = {p = print}
a.p("Hello World") --> Hello World
print = math.sin -- `print' now refers to the sine function
a.p(print(1)) --> 0.841470
sin = a.p -- `sin' now refers to the print function
sin(10, 20) --> 10 20 - 函数的参数也可以是函数:
1
2
3table.sort(network, function (a,b)
return (a.name > b.name)
end)高级函数-闭包
1
2
3
4
5
6定义:一个函数内再定义一个函数,内部函数可以用外部函数的变量
names = {"Peter", "Paul", "Mary"}
grades = {Mary = 10, Paul = 7, Peter = 8}
table.sort(names, function (n1, n2)
return grades[n1] > grades[n2] -- compare the grades
end)
高级函数:非全局函数:
1 | 用法举例: |
高级函数: 尾调用
迭代器
编译执行和错误处理
dofile,loadfile,后者加载文件并编译它
loadstring函数
require:
是lua的高等级函数,用于加载和运行库,大致的说,和dofile一样,不过require支持搜索文件路径和避免重复加载;
c 包:在lua中加载c库的方式:
1 | local path = "/usr/local/lua/lib/libluasocket.so" |
错误处理:
我们必须以最好的方式处理错误。因为Lua是一种扩展语言,通常嵌入到应用程序中,所以当发生错误时,它不能简单地崩溃或退出。相反,每当出现错误时,Lua会结束当前块并返回应用程序。
错误处理方式:
对许多应用程序,不需要去对lua做错误处理,通常应用程序自己会做处理;lua的所有运行,开始于应用程序的一个调用,这个调用让lua运行一个chunk,若出现了错误,会返回错误码,应用程序根据这个来做处理;
若想在lua中处理错误,则:使用pcall
1 | eg: |
错误信息和traceback
通常,当发生错误时,我们需要更多的调试信息,而不仅仅是错误发生的位置。至少,我们需要回溯,显示导致错误的调用的完整堆栈。当pcall返回它的错误消息时,它会销毁堆栈的一部分(从堆栈到错误点的那一部分)。因此,如果我们想要回溯,我们必须在pcall返回之前构建它。为此,Lua提供了xpcall函数。除了要调用的函数外,它还接收到第二个参数,一个错误处理函数。在出现错误的情况下,Lua在堆栈展开之前调用该错误处理程序,以便它可以使用调试库收集关于错误的任何额外信息。两个常见的错误处理程序是debug.debug,它提供一个Lua提示,以便您可以自己检查错误发生时发生了什么(稍后我们将在讨论调试库时看到更多关于它的内容);和调试。traceback,它使用一个traceback构建一个扩展的错误消息。后者是独立解释器用来构建其错误消息的函数。您还可以调用debug。随时回溯以获取当前执行的回溯
print(debug.traceback())
c如何调用lua? lua_cpp
协程:
协程:协作的线程? 主要用于协作的功能
Lua提供了我称为非对称协程的方法。这意味着它有一个用于挂起协同程序执行的函数和另一个用于恢复挂起的协同程序的函数。其他一些语言提供了对称协同程序,其中只有一个函数可以将控制权从一个协同程序转移到另一个协同程序。
lua的协程函数:
- 创建协程:
1
2
3
4co = coroutine.create(function ()
print("hi")
end)
- 打印
print(co) - 协程的状态
1
2
3print(coroutine.status(co)) --> suspended
coroutine.resume(co) --> hi
print(coroutine.status(co)) --> dead 协程运行完就死了; - 协程操作:
yield:
挂起,唤醒后再接着运行;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15co = coroutine.create(function ()
for i=1,10 do
print("co", i)
coroutine.yield()
end
end)
coroutine.resume(co) --> co 1
print(coroutine.status(co)) --> suspended
coroutine.resume(co) --> co 2
coroutine.resume(co) --> co 3
...
coroutine.resume(co) --> co 10
coroutine.resume(co) -- prints nothing
运行结束后 print(coroutine.resume(co))
--> false cannot resume dead coroutine: - lua协程运行在protocted模式,故不会显示error,若发生,但是会返回给resume调用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
221)参数传递:
co = coroutine.create(function (a,b,c)
print("co", a,b,c)
end)
coroutine.resume(co, 1, 2, 3) --> co 1 2 3
2)resume返回例子:resume-yield can exchange data between them.
co = coroutine.create(function (a,b)
coroutine.yield(a + b, a - b)
end)
print(coroutine.resume(co, 20, 10))
结果: true 30 10
3)或者yield返回任何传递的
co = coroutine.create (function ()
print("co", coroutine.yield())
end)
coroutine.resume(co)
coroutine.resume(co, 4, 5) --> co 4 5
4)函数返回值:
co = coroutine.create(function ()
return 6, 7
end)
print(coroutine.resume(co)) --> true 6 7
使用范例:
一个循环挂起,另一个唤醒;生产者-消费者
同步
Pipes and Filters 消费-生产者例子:
1 | first: |
表和对象:
All structures that other languages offer—arrays, records, lists, queues, sets—are represented with tables in Lua.
复杂的结构在lua中是table:
- 用table表示数组:
1
2
3
4a = {} -- new array
for i=1, 1000 do
a[i] = 0
end - 矩阵和多维数组:
1
2
3
4
5
6
7mt = {} -- create the matrix
for i=1,N do
mt[i] = {} -- create a new row
for j=1,M do
mt[i][j] = 0
end
end - 链表:
1
2
3
4
5
6
7list = {next = list, value = v}
To traverse the list, we write:
local l = list
while l do
print(l.value)
l = l.next
end - queue
- sets
- stringbuffer
文件和存储
- Serialization序列化
- 表操作:通常表的操作无非key-value等,可预测,所以提供了一些接口 ,以及原表来提供强大的功能;
- 原表提供算术相关的表级别操作:https://www.lua.org/pil/13.1.html
- 原表提供关系运算表级别操作:https://www.lua.org/pil/13.2.html
- 已定义的库的表操作
- 表操作如下:
- __index
- __newindex
- 默认值表
- 跟踪表操作
- 只读表
环境和_G
介绍:
- lua保存它所有的全局变量在一个常规表里,被叫做环境,更准确的说,是保存在几个环境中,这里忽略多重性;
- 这个常规表环境是_G,_G._G==_G
例如,打印当前环境的所有全局变量:1
for n in pairs(_G) do print(n) end
访问全局变量的方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17loadstring("value = " .. varname)()
or
value = loadstring("return " .. varname)()
value = _G[varname]---效率高,常见
赋值:_G[varname] = value
使用举例:
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
end定义全局变量
非全局环境 :https://www.lua.org/pil/14.3.html
未声明的全局变量,例如相关的库,会带来问题
可以通过setenv改变环境1
2
3
4
5
6a = 1 -- create a global variable
-- change current environment to a new empty table
setfenv(1, {})
print(a)
results in
stdin:5: attempt to call global `print' (a nil value)包
面向对象编程
weak tables