Lua基础语法
# 程序的执行
Lua 交互式编程模式可以通过命令 lua -i 或 lua 来启用:
lua -i "test.lua" 进入交互模式,先执行脚本文件中的内容,比如输入一个数字
dofile("demo.lua") 加载lua文件,比如该文件定义了一些函数,加载该文件后可以直接使用定义好的函数
a = io.read("*number")
# 注释
注释单行
--后边是注释
注释多行
--[[ 中间是要注释的内容 ]]
# 解释器程序
lua [选项参数] [脚本参数]
-e 可直接输入要执行的内容
-l 加载库文件
-i 运行完脚本文件再进入交互模式
# 类型与值
nil(空)
给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉
判断类型是否为nil时需要加引号 type(a) == 'nil' --> trueboolean(布尔)
Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 truenumber(数字)
string(字符串)
a = "one string"
b = string.gsub(a,"one","another")- 字符串由一对双引号或单引号来表示,也可以用 2 个方括号 "[[]]" 来表示"一块"字符串。
- 在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字
- 使用 # 来计算字符串的长度,放在字符串前面
- .. 是字符串连接操作
table(表) 关联数组
- 使用 # 来计算表的大小
- 数组通常以 1 作为索引的初始值
function(函数)
userdata(自定义类型)
可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。thread(线程)
type函数返回数据的类型
# 逻辑运算符
x = x or v 等价于 if not x then x=v end
a and b or c 等价于C语言中 a?b:c
max = (x>y) and x or y
# 运算符优先级
从高到低的顺序:
- ^
- not - (unary)
- * / %
- + -
- ..
- < > <= >= ~= ==
- and
- or
# table构造式
当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。
创建程序块 do ...... end
# 控制语句
- if
if a < b then
return a
else -- 嵌套时使用else if
return b
end
- while
local i = 1
while a[i] do
print(a[i])
i = i + 1
end
- repeat
repeat
line = io.read()
util line ~= ""
- for
- 数值型for
-- var变量,exp1到exp2,exp3为步长
for var=exp1,exp2,exp3 do
<执行体>
end
for i=1,f(x) do
print(i)
end
for i=10,1,-1 do
print(i)
end
- 泛型for
for i,v in ipairs(a) do
print(v)
end
# 函数
在Lua中,函数是一种“第一类值”,它们具有特定的词法域。词法域是指一个函数可以嵌套在另一个函数中,内部的函数可以访问外部函数中的变量。
function add(a)
...
end
unpack(a) a是table类型,经过unpack传入函数,将a的所有元素都传入
# 多重返回值
return ret1,ret2
# 变长参数
Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。
通过 select("#",...) 来获取可变参数的数量
function average(...)
result = 0
local arg={...}
for i,v in ipairs(arg) do
result = result + v
end
print("总共传入 " .. select("#",...) .. " 个数")
return result/select("#",...)
end
print("平均值为",average(10,5,3,4,5,6))
# 闭合函数(closure)
function newCounter()
local i = 0
return function() -- 匿名函数
i = i + 1
return i
end
end
c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2
-- i是“非局部的变量”(upvalue),既不是全局变量,也不是局部变量,而是外部函数的局部变量,该变量用于保持一个计数器
-- 一个closure就是一个函数加上该函数所需访问的所有“非局部的变量”
-- 如果再次调用newCounter,那么它会创建一个新的局部变量,从而也将得到一个新的closure
c2 = newCounter()
print(c2()) --> 1
print(c1()) --> 3
print(c2()) --> 2
-- 因此c1和c2是同一个函数所创建的两个不同的closure,它们各自拥有局部变量i的独立实例。
# 尾调用
当一个函数调用时另一个函数的最后一个动作时,该调用是一条“尾调用”。
function f(x)
return g(x)
end
-- 也就是当f调用完g之后再无其他事情可做了,在这种情况下,程序不需要返回那个“尾调用”所在的函数了。
以后还需要再补充
# 元表(metatable)
meta- 元-
metatable 元数据,描述数据的数据
metatable,允许改变table的行为,每个行为关联了对应的元方法。
setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table): 返回对象的元表(metatable)。
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
-- 以上代码也可以直接写成一行:
mytable = setmetatable({},{})
-- 以下为返回对象元表:
getmetatable(mytable) -- 这回返回mymetatable
# __index 元方法
- 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
- 如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。
mytable = setmetatable({key1 = "value1"}, {
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
-- 实例输出结果为:
-- value1 metatablevalue
# __newindex 元方法
__newindex 元方法用来对表更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
-- 以上实例执行输出结果为:
-- value1
-- nil 新值2
-- 新值1 nil
-- 实例:使用了 rawset 函数来更新表:
mytable = setmetatable({key1 = "value1"}, {
__newindex = function(mytable, key, value)
rawset(mytable, key, "\""..value.."\"")
end
})
mytable.key1 = "new value"
mytable.key2 = 4
print(mytable.key1,mytable.key2)
-- 以上实例执行输出结果为:
-- new value "4"
# 为表添加操作符
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- 两表相加操作
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
for i = 1, table_maxn(newtable) do
table.insert(mytable, table_maxn(mytable)+1,newtable[i])
end
return mytable
end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print(k,v)
end
__add 对应的运算符 '+'.
__sub 对应的运算符 '-'.
__mul 对应的运算符 '*'.
__div 对应的运算符 '/'.
__mod 对应的运算符 '%'.
__unm 对应的运算符 '-'.
__concat 对应的运算符 '..'.
__eq 对应的运算符 '=='.
__lt 对应的运算符 '<'.
__le 对应的运算符 '<='.
# __call 元方法
__call 元方法在 Lua 调用一个值时调用。
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大键值函数 table_maxn,即计算表的元素个数
function table_maxn(t)
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
-- 定义元方法__call
mytable = setmetatable({10}, {
__call = function(mytable, newtable)
sum = 0
for i = 1, table_maxn(mytable) do
sum = sum + mytable[i]
end
for i = 1, table_maxn(newtable) do
sum = sum + newtable[i]
end
return sum
end
})
newtable = {10,20,30}
print(mytable(newtable))
-- 以上实例执行输出结果为:70
# __tostring 元方法
__tostring 元方法用于修改表的输出行为。
mytable = setmetatable({ 10, 20, 30 }, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "表所有元素的和为 " .. sum
end
})
print(mytable)
-- 以上实例执行输出结果为:表所有元素的和为 60
# lua协同程序(coroutine)
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
# 线程和协同程序区别
- 线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
- 在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
- 协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
警告
了解C++的线程后再看