collectgarbage (opt [, arg])
功能:是垃圾收集器的通用接口,用于操作垃圾收集器
参数:
opt:操作方法标志
“Stop”: 停止垃圾收集器
“Restart”: 重启垃圾收集器
“Collect”: 执行一次全垃圾收集循环
“Count”: 返回当前Lua中使用的内存量(以KB为单位)
“Step”: 单步执行一个垃圾收集. 步长 “Size” 由参数arg指定 (大型的值需要多步才能完成),如果要准确指定步长,需要多次实验以达最优效果。如果步长完成一次收集循环,将返回True
“Setpause”: 设置 arg/100 的值作为暂定收集的时长
“Setstepmul”: 设置 arg/100 的值,作为步长的增幅(即新步长=旧步长*arg/100)
dofile (filename)
功能:打开并且执行一个lua块,当忽略参数filename时,将执行标准输入设备(stdin)的内容。返回所有块的返回值。当发生错误时,dofile将错误反射给调用者
注:dofile不能在保护模式下运行
error (message [, level])
功能:终止正在执行的函数,并返回message的内容作为错误信息(error函数永远都不会返回)
通常情况下,error会附加一些错误位置的信息到message头部.
Level参数指示获得错误的位置,
Level=1[默认]:为调用error位置(文件+行号)
Level=2:指出哪个调用error的函数的函数
Level=0:不添加错误位置信息
_G全局环境表(全局变量)
功能:记录全局环境的变量值的表 _G._G = _G
getfenv(f)
功能:返回函数f的当前环境表
参数:f可以为函数或调用栈的级别,级别1[默认]为当前的函数,级别0或其它值将返回全局环境_G
getmetatable(object)
功能:返回指定对象的元表(若object的元表.__metatable项有值,则返回object的元表.__metatable的值),当object没有元表时将返回nil
ipairs (t)
功能:返回三个值 迭代函数、表、0
多用于穷举表的键名和键值对
如:for i,v in ipairs(t) do
end
每次循环将索引赋级i,键值赋给v
注:本函数只能用于以数字索引访问的表 如:t={“1”,”cash”}
load (func [, chunkname])
功能:装载一个块中的函数,每次调用func将返回一个连接前一结的字串,在块结尾处将返回nil
当没有发生错误时,将返回一个编译完成的块作为函数,否则返回nil加上错误信息,此函数的环境为全局环境
chunkname用于错误和调试信息
loadfile ([filename])
功能:与load类似,但装载的是文件或当没有指定filename时装载标准输入(stdin)的内容
loadstring (string [, chunkname])
功能:与load类似,但装载的内容是一个字串
如:assert(loadstring(s))()
next (table [, index])
功能:允许程序遍历表中的每一个字段,返回下一索引和该索引的值。
参数:table:要遍历的表
index:要返回的索引的前一索中的号,当index为nil[]时,将返回第一个索引的值,当索引号为最后一个索引或表为空时将返回nil
注:可以用next(t)来检测表是否为空(此函数只能用于以数字索引的表与ipairs相类似)
ipairs (t)
功能:返回三个值 next函数、表、0
多用于穷举表的键名和键值对
如:for n,v in pairs(t) do
end
每次循环将索引赋级i,键值赋给v
注:本函数只能用于以键名索引访问的表 如:t={id=”1”,name=”cash”}
pcall (f, arg1, ···)
功能:在保护模式下调用函数(即发生的错误将不会反射给调用者)
当调用函数成功能返回true,失败时将返回false加错误信息
print (···)
功能:简单的以tostring方式格式化输出参数的内容
rawequal (v1, v2)
功能:检测v1是否等于v2,此函数不会调用任何元表的方法
rawget (table, index)
功能:获取表中指定索引的值,此函数不会调用任何元表的方法,成功返回相应的值,当索引不存在时返回nil
注:本函数只能用于以数字索引访问的表 如:t={“1”,”cash”}
rawset (table, index, value)
功能:设置表中指定索引的值,此函数不会调用任何元表的方法,此函数将返回table
select (index, ···)
功能:当index为数字将返回所有index大于index的参数:如:select(2,”a”,”b”) 返回 “b”
当index为”#”,则返回参数的总个数(不包括index)
setfenv (f, table)
功能:设置函数f的环境表为table
参数:f可以为函数或调用栈的级别,级别1[默认]为当前的函数,级别0将设置当前线程的环境表
setmetatable (table, metatable)
功能:为指定的table设置元表metatable,如果metatable为nil则取消table的元表,当metatable有__metatable字段时,将触发错误
注:只能为LUA_TTABLE 表类型指定元表
tonumber (e [, base])
功能:尝试将参数e转换为数字,当不能转换时返回nil
base(2~36)指出参数e当前使用的进制,默认为10进制,如tonumber(11,2)=3
tostirng(e)
功能:将参数e转换为字符串,此函数将会触发元表的__tostring事件
type(v)
功能:返回参数的类型名(“nil”,”number”, “string”, “boolean”, “table”, “function”, “thread”, “userdata”)
unpack (list [, i [, j]])
功能:返回指定表的索引的值,i为起始索引,j为结束索引
注:本函数只能用于以数字索引访问的表,否则只会返回nil 如:t={“1”,”cash”}
_VERSION
功能:返回当前Lua的版本号”Lua 5.1”.
xpcall (f, err)
功能:与pcall类似,在保护模式下调用函数(即发生的错误将不会反射给调用者)
但可指定一个新的错误处理函数句柄
当调用函数成功能返回true,失败时将返回false加err返回的结果
lua库函数
这些函数都是Lua编程语言的一部分, 点击这里了解更多.
assert(value) - 检查一个值是否为非nil, 若不是则(如果在wow.exe打开调试命令)显示对话框以及输出错误调试信息
collectgarbage() - 垃圾收集器. (新增于1.10.1)
date(format, time) - 返回当前用户机器上的时间.
error(“error message”,level) - 发生错误时,输出一条定义的错误信息.使用pcall() (见下面)捕捉错误.
gcinfo() - 返回使用中插件内存的占用量(kb)以及当前垃圾收集器的使用量(kB).
getfenv(function or integer) - 返回此表已获取函数的堆栈结构或者堆栈等级
getmetatable(obj, mtable) - 获取当前的元表或者用户数据对象.
loadstring(“Lua code”) - 分析字符串中的lua代码块并且将结果作为一个函数返回
next(table, index) - 返回下一个key,一对表值.允许遍历整个表
pcall(func, arg1, arg2, …) - 受保护调用. 执行函数内容,同时捕获所有的异常和错误.
select(index, list) - 返回选择此列表中的商品数值.或者是此件物品在列表中的索引值
setfenv(function or integer, table) - 设置此表已获取函数的堆栈结构或者堆栈等级
setmetatable(obj, mtable) - 设置当前表的元表或者用户数据对象
time(table) - 返回从一个unix时间值
type(var) - 判断当前变量的类型, “number”, “string”, “table”, “function” 或者 “userdata”.
unpack(table) - 解压一个表.返回当前表中的所有值.
xpcall(func, err) - 返回一个布尔值指示成功执行的函数以及调用失败的错误信息.另外运行函数或者错误的返回值
数学函数
这些表函数同样可以参考Lua函数库(他们都是以math.开头, 详情参阅数学库了解更多信息).
三角函数是没有参考的, 包括角度->弧度的转换.暴雪的版本使用角度.而Lua的标准数学库则使用的弧度.
abs(value) - 返回当前数值的绝对值
acos(value) - 返回此角度值的弧余弦值.
asin(value) - 返回此角度值的弧正弦值
atan(value) - 返回此角度值的弧正切值
atan2(y, x) - 在角度中, 返回Y/X的弧正切值.
ceil(value) - 返回一个整数, 不管小数点后面是多少, 整数部分都进1
cos(degrees) - 返回角度的余弦值
deg(radians) - 弧度转换角度
exp(value) - 返回此值的指数值
floor(value) - 返回此值的整数值
frexp(num) - 返回当前数字小数点后的数值以及小数点后的位数
ldexp(value, 倍数) - 输出此数值的倍数
log(value) - 返回此值的自然对数 (以e为底数)
log10(value) - 返回以10为底数的值
max(value[, values…]) - 在一堆值中查找最大值
min(value[,values…]) - 在一堆值中查找最小值
mod(value,modulus) - 返回此值的余数
rad(degrees) - 角度转换弧度
random([ [lower,] upper]) - 返回一个随机数字 (可选界限为整数值)
randomseed(seed) - 为伪随机数字生成器设定种子
sin(degrees) - 返回当前角度的正弦值
sqrt(value) - 返回数值的平方根值(比如100的平方根为10)
tan(degrees) - 返回当前角度的正切值
字符串库
这些表函数同样可以参考Lua字符串库(他们都是以string.开头, 参考字符串库了解更多信息)
format(formatstring[, value[, …]]) - 格式化字符串
gsub(string,pattern,replacement[, limitCount]) - 全局替换
strbyte(string[, index]) - 转换字符串为整数值(可以指定某个字符).
strchar(asciiCode[, …]) - 转换整数为相对应的字符
strfind(string, pattern[, initpos[, plain]]) - 在一个指定的目标字符串中搜索指定的内容(第三个参数为索引),返回其具体位置.
strlen(string) - 返回当前字符串的字符数
strlower(string) - 将字符串的字母转换为小写格式
strmatch(string, pattern[, initpos]) - 与strfind不同的是,macth返回的是具体值,而find返回的是此值的位置
strrep(seed,count) - 返回一个字符串种子副本的个数
strsub(string, index[, endIndex]) - 返回字符串指定位置的值.
strupper(string) - 将字符串的字母转为大写格式
tonumber(arg[, base]) - 若参数能转为数字则返回一个数值.可以指定转换的类型.默认为十进制整数
tostring(arg) - 转换参数为字符串
下面的字符串函数是wow独有的
strtrim(string) - 去除字符串前后空格
strsplit(delimiter, string) - 分割字符串
strjoin(delimiter, string, string[, …]) - 根据定界符将字符串连接起来
表函数
这些表函数同样可以参考Lua表库 (他们都是以”table.开头”, 查阅Table库 f了解更多信息).
也知道, 很多表都被设计为只有数字索引, 开始于1并且没有结尾(如like {[1] = “foo”, [3] = “bar”} — [2]是不存在的所以为nil值).工作时,与任何其他表并没有差别,但很可能会产生意想不到的结果. 在编写lua中, 这个也就是通常所说的bug
foreach(table,function) - 为表中的每个元素执行函数
foreachi(table,function) - 为表中的每个元素执行函数, 按顺序访问(不推荐, 可以使用ipairs代替)
getn(table) - 当作为一个聊表时, 返回当前表的大小. 现在已经废弃了, 你可以直接使用#符号.使用#(table)代替table.getn(table)
ipairs(table) - 返回一个迭代型整数遍历表。
pairs(table) - 返回一个迭代遍历表
sort(table[, comp]) - 对一个数组进行排序, 还可以指定一个可选的次序函数
tinsert(table[, pos], value) - 将一个元素插入指定的位置(默认在表的最后)
tremove(table[, pos]) - 删除指定位置的元素(默认表最后一个)
Bit Functions
魔兽世界包含了Lua BitLib库(他们都是以 “bit.”开头). 与C的位运算相同.位运算库并非Lua标准函数库的一部分, 但是在WoW 1.9中得到了应用
bit.bnot(a) - 返回一个a的补充
bit.band(w1,…) - 返回w的位与
bit.bor(w1,…) - 返回w的位或
bit.bxor(w1,…) - 返回w的位异或
bit.lshift(a,b) - 返回a向左偏移到b位
bit.rshift(a,b) - 返回a逻辑右偏移到b位
bit.arshift(a,b) - 返回a算术偏移到b位
bit.mod(a,b) - 返回a除以b的整数余数
Lua是一个脚本语言, 使用这些函数来对你的数据结构进行比对是十分慢的. 除非你有一个非常大的数据库以及需要保护的RAM使用, 保存你的信息到几个或个别的变量中.
table
一部分的table函数只对其数组部分产生影响, 而另一部分则对整个table均产生影响. 下面会分开说明.
table.concat(table, sep, start, end)
concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。除了table外, 其他的参数都不是必须的, 分隔符的默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.
sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数, 但如果要指定靠后的参数, 必须同时指定前面的参数.
> tbl = {"alpha", "beta", "gamma"}
> print(table.concat(tbl, ":"))
alpha:beta:gamma
> print(table.concat(tbl, nil, 1, 2))
alphabeta
> print(table.concat(tbl, "/n", 2, 3))
beta
gamma
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
table.insert(table, pos, value)
table.insert()函数在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
> tbl = {"alpha", "beta", "gamma"}
> table.insert(tbl, "delta")
> table.insert(tbl, "epsilon")
> print(table.concat(tbl, ", ")
alpha, beta, gamma, delta, epsilon
> table.insert(tbl, 3, "zeta")
> print(table.concat(tbl, ", ")
alpha, beta, zeta, gamma, delta, epsilon
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
table.maxn(table)
table.maxn()函数返回指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0. 此函数不限于table的数组部分.
> tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"}
> print(#tbl)
3 -- 因为26和之前的数字不连续, 所以不算在数组部分内
> print(table.maxn(tbl))
26
> tbl[91.32] = true
> print(table.maxn(tbl))
91.32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
table.remove(table, pos)
table.remove()函数删除并返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起.
table.sort(table, comp)
table.sort()函数对给定的table进行升序排序.
> tbl = {"alpha", "beta", "gamma", "delta"}
> table.sort(tbl)
> print(table.concat(tbl, ", "))
alpha, beta, delta, gamma
- 1
- 2
- 3
- 4
comp是一个可选的参数, 此参数是一个外部函数, 可以用来自定义sort函数的排序标准.
此函数应满足以下条件: 接受两个参数(依次为a, b), 并返回一个布尔型的值, 当a应该排在b前面时, 返回true, 反之返回false.
例如, 当我们需要降序排序时, 可以这样写:
> sortFunc = function(a, b) return b < a end
> table.sort(tbl, sortFunc)
> print(table.concat(tbl, ", "))
gamma, delta, beta, alpha
- 1
- 2
- 3
- 4
用类似的原理还可以写出更加复杂的排序函数. 例如, 有一个table存有工会三名成员的姓名及等级信息:
guild = {}
table.insert(guild, {
name = "Cladhaire",
class = "Rogue",
level = 70,
})
table.insert(guild, {
name = "Sagart",
class = "Priest",
level = 70,
})
table.insert(guild, {
name = "Mallaithe",
class = "Warlock",
level = 40,
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
对这个table进行排序时, 应用以下的规则: 按等级升序排序, 在等级相同时, 按姓名升序排序.
可以写出这样的排序函数:
function sortLevelNameAsc(a, b)
if a.level == b.level then
return a.name < b.name
else
return a.level < b.level
end
end
测试功能如下:
> table.sort(guild, sortLevelNameAsc)
> for idx, value in ipairs(guild) do print(idx, value.name) end
1, Mallaithe
2, Cladhaire
3, Sagart
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
table.foreachi(table, function(i, v))
会期望一个从 1(数字 1)开始的连续整数范围,遍历table中的key和value逐对进行function(i, v)操作
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};
table.foreachi(t1, function(i, v) print (i, v) end) ; --等价于foreachi(t1, print)
输出结果:
1 2
2 4
3 6
4 8
5 10
6 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
table.foreach(table, function(i, v))
与foreachi不同的是,foreach会对整个表进行迭代
t1 = {2, 4, 6, language="Lua", version="5", 8, 10, 12, web="hello lua"};
table.foreach(t1, function(i, v) print (i, v) end) ;
- 1
- 2
输出结果:
1 2
2 4
3 6
4 8
5 10
6 12
web hello lua
language Lua
version 5
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
table.getn(table)
返回table中元素的个数
t1 = {1, 2, 3, 5};
print(getn(t1))
->4
- 1
- 2
- 3
table.setn(table, nSize)
设置table中的元素个数
5.4 - 字符串操作
该库为字符串操作提供常规函数,例如查找和抽取子串以及模式匹配。在Lua中索引字符串时,第一个字符在位置1(不像C是在0处)。索引允许为负数,被解释为从字符串末尾往回索引。因此,最后一个字符在-1位置,依此类推。
字符串库在表string内提供所有函数。它也给字符串设置元表,其中的__index字段指向string表。因此,你可以使用面向对象风格的字符串函数。例如,string.byte(s, i)可写为s:byte(i)。
string.byte (s [, i [, j]])
返回字符s, s[i+1], ···, s[j]的内部数字代码。i缺省为1;j缺省为i。
注意数字代码不一定是跨平台可移植的。
string.char (···)
接受0获多个整数。返回一个字符串,其长度等于参数个数,其中的每个字符的内部数字代码等于相应的参数。
注意数字代码不一定是跨平台可移植的。
string.dump (function)
返回给定函数的二进制表示的字符串,之后在其上应用loadstring返回函数的拷贝。function必须是不带upvalueLua函数。
string.find (s, pattern [, init [, plain]])
在字符串s中查找pattern的第一个匹配。如果找到则返回它开始和结束处在s中的索引;否则,返回nil。可选的第三参数init是数字,指定从哪儿开始搜索;其缺省值是1并且可为负数。如果真值作为可选的第四参数plain,则关闭模式匹配设备,所以函数执行无格式的“查找子串”操作,pattern中的字符并不被认为是“魔术的(magic)”。注意,如果给出了plain,则init也必须给出。
如果模式具有捕获(capture),则在成功的匹配中被捕获的值也在两个索引后面返回。
string.format (formatstring, ···)
Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). 格式字符串遵循同printf族标准C函数同样的规则。仅有的区别是不支持*、l、L、n、p和h等选项/修饰符,而且有个额外选项q。q选项以可安全地为Lua解释器读取的适当形式格式化字符串:字符串被写在双引号之间,而且字符串中的所有双引号、换行、内嵌的0和反斜杠被恰当地转义。例如,调用
string.format('%q', 'a string with "quotes" and /n new line')
- 1
产生字符串:
"a string with /"quotes/" and /
new line"
- 1
- 2
选项c、d、E、e、f, g、G、i、o、u、X和x都预期得到数字作为参数,然而q和s期望得到字符串。
该函数不接受含有内嵌的0的字符串值,除了作为q选项的参数。
string.gmatch (s, pattern)
返回一个迭代器函数,每次调用返回来自pattern的下一个捕获,从字符串s开头直到结尾。如果pattern没指定捕获则每次调用产生整个匹配。
作为例子,下面的循环
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
print(w)
end
- 1
- 2
- 3
- 4
将迭代来自字符串s的所有单词,每行打印一个。下一个例子从给定的字符串收集所有的键=值对放在表中:
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "^(%w+)=(%w+)") do
t[k] = v
end
- 1
- 2
- 3
- 4
- 5
对于该函数,模式起始处的‘^’不能作为锚点,因为这会阻止迭代。
string.gsub (s, pattern, repl [, n])
返回s的拷贝,其中出现的所有(或前n个,如果指定)pattern被替换为repl——可以是字符串、表或函数,指定的替换串。gsub也返回出现的匹配的总数作为第二个值。
如果repl是字符串,它的值被用作替换式。字符%用作转义字符:repl中的任何形如%n的序列代表第n个捕获的子串(见下面),其中n在1和9之间。序列%0代表整个匹配。序列%%代表单个%。
如果repl是表,则对于每个匹配,用第一个捕获作为键查询表;如果模式未指定捕获,则整个匹配被用作键。
如果repl是函数,则每次匹配发生时都按顺序传入所有捕获的子串作为参数调用该函数;如果模式没指定捕获,则整个匹配作为单个参数传入。
如果表查询或函数调用返回的结果是个字符串或数字,则被用作替换串;否则,如果是false或nil,则不发生替换(即原始匹配被保持在字符串中)。
这里有一些例子:
x = string.gsub("hello world", "(%w+)", "%1 %1")
--> x="hello hello world world"
x = string.gsub("hello world", "%w+", "%0 %0", 1)
--> x="hello hello world"
x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
--> x="world hello Lua from"
x = string.gsub("home = $HOME</span>, user = <span class="hljs-variable">$USER", "%$(%w+)", os.getenv)
--> x="home = /home/roberto, user = roberto"
x = string.gsub("4+5 = $return</span> 4+5<span class="hljs-variable">$", "%$</span>(.-)<span class="hljs-variable">%$", function (s)
return loadstring(s)()
end)
--> x="4+5 = 9"
local t = {name="lua", version="5.1"}
x = string.gsub("$name</span>-<span class="hljs-variable">$version.tar.gz", "%$(%w+)", t)
--> x="lua-5.1.tar.gz"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
string.len (s)
接受字符串并返回其长度。空串”“长度为0。内嵌的0被计算在内,所以”a/000bc/000”长度为5。
string.lower (s)
接受字符串并返回其所有大写字母变为小写的拷贝。所有其他字符不变。大写字母的定义依赖于但前locale。
string.match (s, pattern [, init])
在字符串s中查找pattern的首次匹配。如果找到一个,则返回来自模式的捕获;否则返回nil。如果pattern未指定捕获则返回整个匹配。可选的第三个参数init是数字,指定从哪儿开始搜索;其缺省值是1并且可为负。
string.rep (s, n)
返回字符串s的n个拷贝拼接字符串。
string.reverse (s)
返回字符串s的颠倒的字符串。
string.sub (s, i [, j])
返回s的子串,它起始于i并延续到j;i和j可为负数。如果省略j,则它被假定为-1(同字符串长度一样)。特别地,调用string.sub(s,1,j)返回s长为j的前缀,而且string.sub(s, -i)返回s长为i的后缀。
string.upper (s)
接受字符串并返回其所有小写字母变为大写的拷贝。所有其他字符不变。小写字母的定义依赖于但前locale。
5.4.1 - 模式
字符类(Character Class):
一个字符类被用于表示一组字符。允许用下面的组合描述字符类:
* x: (此处x不是魔术字符^$()%.[]*+-?中的一个)表示字符x本身。 * .: (一个点)表示所有字符。 * %a: 表示所有字母。 * %c: 表示所有控制字符。 * %d: 表示所有十进制数字。 * %l: 表示所有小写字母。 * %p: 表示所有标点符号。 * %s: 表示所有空白字符。 * %u: 表示所有大写字母。 * %w: 表示所有字母数字字符。 * %x: 表示所有十六进制数字。 * %z: 表示0值字符。 * %x: (此处x是任何非字母数字字符)表示字符x。这是转义魔术字符的标准方式。当被用于在模式中表示自身时,任何标点符号(甚至非魔术的)都能前缀一个‘%’。 * [set]: 表示set中的所有字符的联合构成的分类。通过用‘-’分隔截止字符可以指定某个范围的字符。上面描述的所有种类的%x都可用作set的部件。set中的所有其他字符表示它们自身。例如[%w_](或[_%w])表示所有字母数字字符和下划线,[0-7]表示八进制数字,[0-7%l%-]表示八进制数字和小写字母以及‘-’字符。 字符范围和字符类之间的相互作用是未定义的。因此类似[%a-z]或[a-%%]的模式没有意义。 * [^set]: 表示set的补集,其中的set在上面解释了。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
所有单字母表示的字符类(%a、%c,等等),相应的大写字母表示该字符类的补集。例如,%S表示所有非空白符。
字母、空白和其他字符组合的定义依赖于当前locale。特别地,字符类[a-z]可能不等于%l。 模式项(Pattern Item):
模式项可能为
* 单个字符类,它匹配该类中的任意单个字符; * 后跟‘*’的单个字符类,它匹配该类中的0或多个字符。这些重复项将总是匹配最长的可能序列; * 后跟‘+’的单个字符类,它匹配该类中的1或多个字符。这些重复项将总是匹配最长的可能序列; * 后跟‘-’的单个字符类,它也匹配该类中的0或多个字符。与‘*’不同,这些重复项将总是匹配最短的可能序列; * 后跟‘?’的单个字符类,它匹配出现0或1次该类中的字符; * %n,其中n在1和9之间;这种项匹配一个等价于捕获的字符串的第n个子串(见下面); * %bxy其中x和y是两个不同的字符;这种项匹配始于x终于y的字符串,并且x和y是对称的。这表示,如果一个人从左到右读字符串,对x计数为+1,对y计数为-1,结尾的y是第一个遇到计数为0的y
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
。例如,项%b()匹配带有平衡的圆括号的表达式。
模式(Pattern):
模式是一系列的模式项。在模式开头的‘^’将匹配固定在源串的开头。 在模式结尾的‘’将匹配固定在源串的结尾。在其他位置上,‘^’和‘” role=”presentation”>’将匹配固定在源串的结尾。在其他位置上,‘^’和‘’将匹配固定在源串的结尾。在其他位置上,‘^’和‘’没有特殊含义,表示它们自身。
捕获(Captures):
模式可以含有括在圆括号内的子模式;它们描述捕获。当成功进行一个匹配,源串中匹配捕获的子串被存储(捕获)以便将来使用。捕获根据它们的左圆括号进行编号。例如,在模式”(a*(.)%w(%s*))”中,字符串的匹配”a*(.)%w(%s*)”的部分作为第一个捕获被存储(因此被编号为1);匹配“.”的字符被捕获并编号为2,匹配“%s*”的部分被编号为3。
作为一种特殊情况,空捕获()捕获当前字符串位置(一个数字)。例如,如果我们把模式”()aa()”用于字符串”flaaap”,将有两个捕获:3和5。
模式不能含有内嵌的0。使用%z代替。
Lua模式匹配—主要注意其字符部分
模式匹配函数
在string库中功能最强大的函数是:
string.find(字符串查找) string.gsub(全局字符串替换) string.gfind(全局字符串查找)
string.gmatch(返回查找到字符串的迭代器)
这些函数都是基于模式匹配的。与其他脚本语言不同的是,Lua并不使用POSIX规范的正则表达式[4](也写作regexp)来进行模式匹配。主要的原因出于程序大小方面的考虑:实现一个典型的符合POSIX标准的regexp大概需要4000行代码,这比整个Lua标准库加在一起都大。权衡之下,Lua中的模式匹配的实现只用了 500行代码,当然这意味着不可能实现POSIX所规范的所有更能。然而,Lua中的模式匹配功能是很强大的,并且包含了一些使用标准POSIX模式匹配不容易实现的功能。
string.gmatch(str, pattern)
这是一个返回迭代器的函数. 实际的用例如下:
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
print(w)
end
- 1
- 2
- 3
- 4
这里是一个捕获并将配对字符分别存到不同变量的例子:
t = {}
s = "from=world, to=Lua"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
t[k]=v
end
for k, v in pairs(t) do
print(k, v)
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
string.gsub(str, pattern, repl, n)
string.gsub()函数根据给定的配对表达式对源字符串str进行配对, 同时返回源字符串的一个副本, 该副本中成功配对的所有子字符串都将被替换. 函数还将返回成功配对的次数.实际的替换行为由repl参数的类型决定:
当repl为字符串时, 所有成功配对的子字符串均会被替换成指定的repl字串.
当repl为table时, 对每个成功配对的子字符串, 函数均会试图寻找以其为key值的table中的元素, 并返回该元素. 如果该配对包含任何捕获信息, 则以编号为1号的捕获作为key值进行查找.
当repl为函数时, 每个成功配对的子字符串均会作为参数被传入到该函数中去.
在repl是table或函数时, 如果该table或函数返回了字串或数字的值, 这个值依然会被用于替换副本字串中的配对子字串. 如果该table/函数返回的值为空, 将不发生替换.
n参数可选, 当它被指定时, string.gsub()函数只对源字符串中的前n个成功配对的成员进行操作.
以下是几个例子:
> print(string.gsub("hello world", "(%w+)", "%1 %1"))
hello hello world world 2
> print(string.gsub("hello Lua", "(%w+)%s*(%w+)", "%2 %1"))
Lua hello 1
> string.gsub("hello world", "%w+", print)
hello world 2
> lookupTable = {["hello"] = "hola", ["world"] = "mundo"}
> print(string.gsub("hello world", "(%w+)", lookupTable))
hola mundo 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
string.match(str, pattern, init)
string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1.
在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil.
string.match("abcdaef", "a")
-> a
- 1
- 2
string.reverse(str)
返回一个字符串的倒序排列
string.reverse(“abcde”)
->edcba
string.dump(function)
返回指定函数的二进制代码(函数必须是一个Lua函数,并且没有上值)
string.find(str, pattern, init, plain)
string.find 的基本应用就是用来在目标串(subject string)内搜索匹配指定的模式的串。函数如果找到匹配的串返回他的位置,否则返回nil.最简单的模式就是一个单词,仅仅匹配单词本身。比如,模式 ‘hello’仅仅匹配目标串中的”hello”。当查找到模式的时候,函数返回两个值:匹配串开始索引和结束索引。
s = "hello world"
string.find(s, "hello") --> 1 5
string.find(s, "world") --> 7 11
string.find(s, "l") --> 3 3
string.find(s, "lll") --> nil
- 1
- 2
- 3
- 4
- 5
string.find函数第三个参数是可选的:标示目标串中搜索的起始位置。当我们想查找目标串中所有匹配的子串的时候,这个选项非常有用。我们可以不断的循环搜索,每一次从前一次匹配的结束位置开始。下面看一个例子,下面的代码用一个字符串中所有的新行构造一个表:
local t = {} -- 存放回车符的位置
local i = 0
while true do
i = string.find(s, "/n", i+1) -- 查找下一行
if i == nil then break end
table.insert(t, i)
end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
string.sub(str,sPos,ePos)
string.gsub的功能是截取字符串,他从指定起始位置截取一个字符串。string.sub可以利用string.find返回的值截取匹配的子串。
对简单模式而言,匹配的就是其本身
s = "hello world"
local i, j = string.find(s, "hello") --> 1 5
string.sub(s, i, j) --> hello
- 1
- 2
- 3
string.gsub(str, sourcestr, desstr)
string.gsub的基本作用是用来查找匹配模式的串,并将使用替换串其替换掉:
string.gsub函数有三个参数:目标串,模式串,替换串。
s = string.gsub("Lua is cute", "cute", "great")
print(s) --> Lua is great
s = string.gsub("all lii", "l", "x")
print(s) --> axx xii
s = string.gsub("Lua is great", "perl", "tcl")
print(s) --> Lua is great
第四个参数是可选的,用来限制替换的范围:
s = string.gsub("all lii", "l", "x", 1)
print(s) --> axl lii
s = string.gsub("all lii", "l", "x", 2)
print(s) --> axx lii
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
string.gsub的第二个返回值表示他进行替换操作的次数。例如,下面代码涌来计算一个字符串中空格出现的次数:
_, count = string.gsub(str, ” “, ” “)
(注意,_ 只是一个哑元变量)
模式
你还可以在模式串中使用字符类。字符类指可以匹配一个特定字符集合内任何字符的模式项。比如,字符类%d匹配任意数字。所以你可以使用模式串’%d%d/%d%d/%d%d%d%d’搜索dd/mm/yyyy格式的日期:
s = “Deadline is 30/05/1999, firm”
date = “%d%d/%d%d/%d%d%d%d”
print(string.sub(s, string.find(s, date))) –> 30/05/1999
下面的表列出了Lua支持的所有字符类:
单个字符(除^$()%.[]*+-?外): 与该字符自身配对
.(点): 与任何字符配对
%a: 与任何字母配对
%c: 与任何控制符配对(例如/n)
%d: 与任何数字配对
%l: 与任何小写字母配对
%p: 与任何标点(punctuation)配对
%s: 与空白字符配对
%u: 与任何大写字母配对
%w: 与任何字母/数字配对
%x: 与任何十六进制数配对
%z: 与任何代表0的字符配对
%x(此处x是非字母非数字字符): 与字符x配对. 主要用来处理表达式中有功能的字符(^$()%.[]*+-?)的配对问题, 例如%%与%配对
[数个字符类]: 与任何[]中包含的字符类配对. 例如[%w_]与任何字母/数字, 或下划线符号(_)配对
当上述的字符类用大写书写时, 表示与非此字符类的任何字符配对. 例如, %S表示与任何非空白字符配对.例如,’%A’非字母的字符
print(string.gsub("hello, up-down!", "%A", "."))
--> hello..up.down. 4
- 1
- 2
(数字4不是字符串结果的一部分,他是gsub返回的第二个结果,代表发生替换的次数。下面其他的关于打印gsub结果的例子中将会忽略这个数值。)在模式匹配中有一些特殊字符,他们有特殊的意义,Lua中的特殊字符如下:
( ) . % + - * ? [ ^ $
‘%’ 用作特殊字符的转义字符,因此 ‘%.’ 匹配点;’%%’ 匹配字符 ‘%’。转义字符 ‘%’不仅可以用来转义特殊字符,还可以用于所有的非字母的字符。当对一个字符有疑问的时候,为安全起见请使用转义字符转义他。
对Lua 而言,模式串就是普通的字符串。他们和其他的字符串没有区别,也不会受到特殊对待。只有他们被用作模式串用于函数的时候,’%’ 才作为转义字符。所以,如果你需要在一个模式串内放置引号的话,你必须使用在其他的字符串中放置引号的方法来处理,使用 ‘/’ 转义引号,’/’ 是Lua的转义符。你可以使用方括号将字符类或者字符括起来创建自己的字符类(译者:Lua称之为char-set,就是指传统正则表达式概念中的括号表达式)。比如,’[%w_]’ 将匹配字母数字和下划线,’[01]’ 匹配二进制数字,’[%[%]]’ 匹配一对方括号。下面的例子统计文本中元音字母出现的次数:
_, nvow = string.gsub(text, “[AEIOUaeiou]”, “”)
在char -set中可以使用范围表示字符的集合,第一个字符和最后一个字符之间用连字符连接表示这两个字符之间范围内的字符集合。大部分的常用字符范围都已经预定义好了,所以一般你不需要自己定义字符的集合。比如,’%d’ 表示 ‘[0-9]’;’%x’ 表示 ‘[0-9a-fA-F]’。然而,如果你想查找八进制数,你可能更喜欢使用 ‘[0-7]’ 而不是 ‘[01234567]’。你可以在字符集(char-set)的开始处使用 ‘^’ 表示其补集:’[^0-7]’ 匹配任何不是八进制数字的字符;’[^/n]’ 匹配任何非换行符户的字符。记住,可以使用大写的字符类表示其补集:’%S’ 比 ‘[^%s]’ 要简短些。
Lua的字符类依赖于本地环境,所以 ‘[a-z]’ 可能与 ‘%l’ 表示的字符集不同。在一般情况下,后者包括 ‘ç’ 和 ‘ã’,而前者没有。应该尽可能的使用后者来表示字母,除非出于某些特殊考虑,因为后者更简单、方便、更高效。
可以使用修饰符来修饰模式增强模式的表达能力,Lua中的模式修饰符有四个:
- 匹配前一字符1次或多次
- 匹配前一字符0次或多次
- 匹配前一字符0次或多次
? 匹配前一字符0次或1次
‘+’,匹配一个或多个字符,总是进行最长的匹配。比如,模式串 ‘%a+’ 匹配一个或多个字母或者一个单词:
print(string.gsub(“one, and two; and three”, “%a+”, “word”))
–> word, word word; word word
‘%d+’ 匹配一个或多个数字(整数):
i, j = string.find(“the number 1298 is even”, “%d+”)
print(i,j) –> 12 15
‘’ 与 ‘+’ 类似,但是他匹配一个字符0次或多次出现. 一个典型的应用是匹配空白。比如,为了匹配一对圆括号()或者括号之间的空白,可以使用 ‘%(%s%)’。( ‘%s*’ 用来匹配0个或多个空白。由于圆括号在模式中有特殊的含义,所以我们必须使用 ‘%’ 转义他。)再看一个例子,’[%a][%w]*’ 匹配Lua程序中的标示符:字母或者下划线开头的字母下划线数字序列。
‘-’ 与 ‘’ 一样,都匹配一个字符的0次或多次出现,但是他进行的是最短匹配。某些时候这两个用起来没有区别,但有些时候结果将截然不同。比如,如果你使用模式 ‘[_%a][_%w]-’ 来查找标示符,你将只能找到第一个字母,因为 ‘[_%w]-’ 永远匹配空。另一方面,假定你想查找C程序中的注释,很多人可能使用 ‘/%.%/’(也就是说 “/” 后面跟着任意多个字符,然后跟着 “/” )。然而,由于 ‘.’ 进行的是最长匹配,这个模式将匹配程序中第一个 “/” 和最后一个 “*/” 之间所有部分:
test = “int x; /* x / int y; / y */”
print(string.gsub(test, “/%.%*/”, “”))
–> int x;
然而模式 ‘.-’ 进行的是最短匹配,她会匹配 “/” 开始到第一个 “/” 之前的部分:
test = “int x; /* x / int y; / y */”
print(string.gsub(test, “/%.-%/”, “”))
–> int x; int y;
‘?’ 匹配一个字符0次或1次。举个例子,假定我们想在一段文本内查找一个整数,整数可能带有正负号。模式 ‘[+-]?%d+’ 符合我们的要求,它可以匹配像 “-12”、”23” 和 “+1009” 等数字。’[+-]’ 是一个匹配 ‘+’ 或者 ‘-’ 的字符类;接下来的 ‘?’ 意思是匹配前面的字符类0次或者1次。
与其他系统的模式不同的是,Lua中的修饰符不能用字符类;不能将模式分组然后使用修饰符作用这个分组。比如,没有一个模式可以匹配一个可选的单词(除非这个单词只有一个字母)。下面我将看到,通常你可以使用一些高级技术绕开这个限制。
以 ‘^’ 开头的模式只匹配目标串的开始部分,相似的,以 ‘$’ 结尾的模式只匹配目标串的结尾部分。这不仅可以用来限制你要查找的模式,还可以定位(anchor)模式。比如:
if string.find(s, “^%d”) then …
检查字符串s是否以数字开头,而
if string.find(s, “^[+-]?%d+$”) then …
检查字符串s是否是一个整数。
‘%b’ 用来匹配对称的字符。常写为 ‘%bxy’ ,x和y是任意两个不同的字符;x作为匹配的开始,y作为匹配的结束。比如,’%b()’ 匹配以 ‘(’ 开始,以 ‘)’ 结束的字符串:
print(string.gsub(“a (enclosed (in) parentheses) line”, “%b()”, “”))
–> a line
常用的这种模式有:’%b()’ ,’%b[]’,’%b%{%}’ 和 ‘%b<>’。你也可以使用任何字符作为分隔符。
Lua中的字符串函数库–这个好一点
Lua解释器对字符串的支持很有限。一个程序可以创建字符串并连接字符串,但不能截取子串,检查字符串的大小,检测字符串的内容。在Lua中操纵字符串的功能基本来自于string库。
字符串库中的一些函数是非常简单的:
string.len(s) 返回字符串s的长度;
string.rep(s, n) 返回重复n次字符串s的串;你使用string.rep(“a”, 2^20)可以创建一个1M bytes的字符串(比如,为了测试需要);
string.lower(s) 将s中的大写字母转换成小写(string.upper将小写转换成大写)。如果你想不关心大小写对一个数组进行排序的话,你可以这样:
table.sort(a, function (a, b) return string.lower(a) < string.lower(b) end)
string.upper(s) 将s中的小写字母转换成大写
string.upper和string.lower都依赖于本地环境变量。所以,如果你在 European Latin-1环境下,表达式:
string.upper(“a??o”) –> “A??O”
string.sub(s,i,j) 函数截取字符串s的从第i个字符到第j个字符之间的串。Lua中,字符串的第一个字符索引从1开始。你也可以使用负索引,负索引从字符串的结尾向前计数:-1指向最后一个字符,-2指向倒数第二个,以此类推。所以, string.sub(s, 1, j)返回字符串s的长度为j的前缀;string.sub(s, j, -1)返回从第j个字符开始的后缀。如果不提供第3个参数,默认为-1,因此我们将最后一个调用写为string.sub(s, j);string.sub(s, 2, -2)返回去除第一个和最后一个字符后的子串。
s = “[in brackets]” print(string.sub(s, 2, -2)) –> in brackets
记住:Lua中的字符串是恒定不变的。string.sub函数以及Lua中其他的字符串操作函数都不会改变字符串的值,而是返回一个新的字符串。一个常见的错误是:
string.sub(s, 2, -2)
认为上面的这个函数会改变字符串s的值。如果你想修改一个字符串变量的值,你必须将变量赋给一个新的字符串:
s = string.sub(s, 2, -2)
string.char函数和string.byte函数用来将字符在字符和数字之间转换。string.char获取0个或多个整数,将每一个数字转换成字符,然后返回一个所有这些字符连接起来的字符串。string.byte(s, i)将字符串s的第i个字符的转换成整数;第二个参数是可选的,缺省情况下i=1。下面的例子中,我们假定字符用ASCII表示:
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
- 1
- 2
- 3
- 4
- 5
上面最后一行,我们使用负数索引访问字符串的最后一个字符。
Lua提供了string.format()函数来生成具有特定格式的字符串, 函数的第一个参数是格式(formatstring), 之后是对应格式中每个代号的各种数据. 由于格式字符串的存在, 使得产生的长字符串可读性大大提高了. 这个函数的格式很像C语言中的printf().函数string.format在用来对字符串进行格式化的时候,特别是字符串输出,是功能强大的工具。这个函数有两个参数,你完全可以照C语言的printf来使用这个函数。第一个参数为格式化串:由指示符和控制格式的字符组成。指示符后的控制格式的字符可以为:十进制’d’;十六进制’x’;八进制’o’;浮点数’f’;字符串’s’。在指示符’%’和控制格式字符之间还可以有其他的选项:用来控制更详细的格式,比如一个浮点数的小数的位数:
格式字符串可能包含以下的转义码:
%c - 接受一个数字, 并将其转化为ASCII码表中对应的字符
%d, %i - 接受一个数字并将其转化为有符号的整数格式
%o - 接受一个数字并将其转化为八进制数格式
%u - 接受一个数字并将其转化为无符号整数格式
%x - 接受一个数字并将其转化为十六进制数格式, 使用小写字母
%X - 接受一个数字并将其转化为十六进制数格式, 使用大写字母
%e - 接受一个数字并将其转化为科学记数法格式, 使用小写字母e
%E - 接受一个数字并将其转化为科学记数法格式, 使用大写字母E
%f - 接受一个数字并将其转化为浮点数格式
%g(%G) - 接受一个数字并将其转化为%e(%E, 对应%G)及%f中较短的一种格式
%q - 接受一个字符串并将其转化为可安全被Lua编译器读入的格式
%s - 接受一个字符串并按照给定的参数格式化该字符串
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
为进一步细化格式, 可以在%号后添加参数. 参数将以如下的顺序读入:
(1) 符号: 一个+号表示其后的数字转义符将让正数显示正号. 默认情况下只有负数显示符号.
(2) 占位符: 一个0, 在后面指定了字串宽度时占位用. 不填时的默认占位符是空格.
(3) 对齐标识: 在指定了字串宽度时, 默认为右对齐, 增加-号可以改为左对齐.
(4) 宽度数值
(5) 小数位数/字串裁切: 在宽度数值后增加的小数部分n, 若后接f(浮点数转义符, 如%6.3f)则设定该浮点数的小数只保留n位, 若后接s(字符串转义符, 如%5.3s)则设定该字符串只显示前n位.
在这些参数的后面则是上述所列的转义码类型(c, d, i, f, …).
print(string.format("pi = %.4f", PI))
--> pi = 3.1416
d = 5; m = 11; y = 1990
print(string.format("%02d/%02d/%04d", d, m, y))
--> 05/11/1990
tag, title = "h1", "a title"
print(string.format("<%s>%s</%s>", tag, title, tag))
--> <h1>a title</h1>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
第一个例子,%.4f代表小数点后面有4位小数的浮点数。第二个例子%02d代表以固定的两位显示十进制数,不足的前面补0。而%2d前面没有指定0,不足两位时会以空白补足。对于格式串部分指示符得详细描述清参考lua手册,或者参考C手册,因为Lua调用标准C的printf函数来实现最终的功能。
以下是一些例子:
string.format("%%c: %c", 83) 输出S
string.format("%+d", 17.0) 输出+17
string.format("%05d", 17) 输出00017
string.format("%o", 17) 输出21
string.format("%u", 3.14) 输出3
string.format("%x", 13) 输出d
string.format("%X", 13) 输出D
string.format("%e", 1000) 输出1.000000e+03
string.format("%E", 1000) 输出1.000000E+03
string.format("%6.3f", 13) 输出13.000
string.format("%q", "One/nTwo") 输出"One/
Two"
string.format("%s", "monkey") 输出monkey
string.format("%10s", "monkey") 输出 monkey
string.format("%5.3s", "monkey") 输出 mon
Lua C API中文函数手册
typedef void * (*lua_Alloc) (void *ud,
void *ptr,
size_t osize,
size_t nsize);
Lua 状态机中使用的内存分配器函数的类型。内存分配函数必须提供一个功能类似于 realloc 但又不完全相同的函数。它的参数有 ud ,一个由 lua_newstate 传给它的指针; ptr ,一个指向已分配出来或是将被重新分配或是要释放的内存块指针; osize ,内存块原来的尺寸; nsize ,新内存块的尺寸。如果且只有 osize 是零时,ptr 为 NULL 。当 nsize 是零,分配器必须返回 NULL;如果 osize 不是零,分配器应当释放掉 ptr 指向的内存块。当 nsize 不是零,若分配器不能满足请求时,分配器返回 NULL 。当 nsize 不是零而 osize 是零时,分配器应该和 malloc 有相同的行为。当 nsize 和 osize 都不是零时,分配器则应和 realloc 保持一样的行为。 Lua 假设分配器在 osize >= nsize 时永远不会失败。
这里有一个简单的分配器函数的实现。这个实现被放在补充库中,由 luaL_newstate 提供。
static void *l_alloc (void *ud, void *ptr, size_t osize,
size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
这段代码假设 free(NULL) 啥也不影响,而且 realloc(NULL, size) 等价于 malloc(size)。这两点是 ANSI C 保证的行为。
lua_atpanic
lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
设置一个新的 panic (恐慌) 函数,并返回前一个。
如果在保护环境之外发生了任何错误, Lua 就会调用一个 panic 函数,接着调用 exit(EXIT_FAILURE),这样就开始退出宿主程序。你的 panic 函数可以永远不返回(例如作一次长跳转)来避免程序退出。
panic 函数可以从栈顶取到出错信息。
lua_call
void lua_call (lua_State *L, int nargs, int nresults);
调用一个函数。
要调用一个函数请遵循以下协议:首先,要调用的函数应该被压入堆栈;接着,把需要传递给这个函数的参数按正序压栈;这是指第一个参数首先压栈。最后调用一下 lua_call; nargs 是你压入堆栈的参数个数。当函数调用完毕后,所有的参数以及函数本身都会出栈。而函数的返回值这时则被压入堆栈。返回值的个数将被调整为 nresults 个,除非 nresults 被设置成 LUA_MULTRET。在这种情况下,所有的返回值都被压入堆栈中。 Lua 会保证返回值都放入栈空间中。函数返回值将按正序压栈(第一个返回值首先压栈),因此在调用结束后,最后一个返回值将被放在栈顶。
被调用函数内发生的错误将(通过 longjmp)一直上抛。
下面的例子中,这行 Lua 代码等价于在宿主程序用 C 代码做一些工作:
a = f("how", t.x, 14)
- 1
这里是 C 里的代码:
lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* 将调用的函数 */
lua_pushstring(L, "how"); /* 第一个参数 */
lua_getfield(L, LUA_GLOBALSINDEX, "t"); /* table 的索引 */
lua_getfield(L, -1, "x"); /* 压入 t.x 的值(第 2 个参数)*/
lua_remove(L, -2); /* 从堆栈中移去 't' */
lua_pushinteger(L, 14); /* 第 3 个参数 */
lua_call(L, 3, 1); /* 调用 'f',传入 3 个参数,并索取 1 个返回值 */
lua_setfield(L, LUA_GLOBALSINDEX, "a"); /* 设置全局变量 'a' */
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
注意上面这段代码是“平衡”的:到了最后,堆栈恢复成原由的配置。这是一种良好的编程习惯。
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
- 1
C 函数的类型。
为了正确的和 Lua 通讯,C 函数必须使用下列定义了参数以及返回值传递方法的协议: C 函数通过 Lua 中的堆栈来接受参数,参数以正序入栈(第一个参数首先入栈)。因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。第一个参数(如果有的话)在索引 1 的地方,而最后一个参数在索引 lua_gettop(L) 处。当需要向 Lua 返回值的时候,C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入),然后返回这些返回值的个数。在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值。
下面这个例子中的函数将接收若干数字参数,并返回它们的平均数与和:
static int foo (lua_State *L) {
int n = lua_gettop(L); /* 参数的个数 */
lua_Number sum = 0;
int i;
for (i = 1; i <= n; i++) {
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L, i);
}
lua_pushnumber(L, sum/n); /* 第一个返回值 */
lua_pushnumber(L, sum); /* 第二个返回值 */
return 2; /* 返回值的个数 */
}
lua_checkstack
int lua_checkstack (lua_State *L, int extra);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
确保堆栈上至少有 extra 个空位。如果不能把堆栈扩展到相应的尺寸,函数返回 false 。这个函数永远不会缩小堆栈;如果堆栈已经比需要的大了,那么就放在那里不会产生变化。
lua_close
void lua_close (lua_State *L);
销毁指定 Lua 状态机中的所有对象(如果有垃圾收集相关的元方法的话,会调用它们),并且释放状态机中使用的所有动态内存。在一些平台上,你可以不必调用这个函数,因为当宿主程序结束的时候,所有的资源就自然被释放掉了。另一方面,长期运行的程序,比如一个后台程序或是一个 web 服务器,当不再需要它们的时候就应该释放掉相关状态机。这样可以避免状态机扩张的过大。
lua_concat
void lua_concat (lua_State *L, int n);
连接栈顶的 n 个值,然后将这些值出栈,并把结果放在栈顶。如果 n 为 1 ,结果就是一个字符串放在栈上(即,函数什么都不做);如果 n 为 0 ,结果是一个空串。 连接依照 Lua 中创建语义完成(参见 §2.5.4 )。
lua_cpcall
int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
以保护模式调用 C 函数 func 。 func 只有能从堆栈上拿到一个参数,就是包含有 ud 的 light userdata。当有错误时, lua_cpcall 返回和 lua_pcall 相同的错误代码,并在栈顶留下错误对象;否则它返回零,并不会修改堆栈。所有从 func 内返回的值都会被扔掉。
lua_createtable
void lua_createtable (lua_State *L, int narr, int nrec);
创建一个新的空 table 压入堆栈。这个新 table 将被预分配 narr 个元素的数组空间以及 nrec 个元素的非数组空间。当你明确知道表中需要多少个元素时,预分配就非常有用。如果你不知道,可以使用函数 lua_newtable。
lua_dump
int lua_dump (lua_State *L, lua_Writer writer, void *data);
把函数 dump 成二进制 chunk 。函数接收栈顶的 Lua 函数做参数,然后生成它的二进制 chunk 。若被 dump 出来的东西被再次加载,加载的结果就相当于原来的函数。当它在产生 chunk 的时候,lua_dump 通过调用函数 writer (参见 lua_Writer)来写入数据,后面的 data 参数会被传入 writer 。
最后一次由写入器 (writer) 返回值将作为这个函数的返回值返回; 0 表示没有错误。
这个函数不会把 Lua 返回弹出堆栈。
lua_equal
int lua_equal (lua_State *L, int index1, int index2);
如果依照 Lua 中 == 操作符语义,索引 index1 和 index2 中的值相同的话,返回 1 。否则返回 0 。如果任何一个索引无效也会返回 0。
lua_error
int lua_error (lua_State *L);
产生一个 Lua 错误。错误信息(实际上可以是任何类型的 Lua 值)必须被置入栈顶。这个函数会做一次长跳转,因此它不会再返回。(参见 luaL_error)。
lua_gc
int lua_gc (lua_State *L, int what, int data);
控制垃圾收集器。
这个函数根据其参数 what 发起几种不同的任务:
LUA_GCSTOP: 停止垃圾收集器。
LUA_GCRESTART: 重启垃圾收集器。
LUA_GCCOLLECT: 发起一次完整的垃圾收集循环。
LUA_GCCOUNT: 返回 Lua 使用的内存总量(以 K 字节为单位)。
LUA_GCCOUNTB: 返回当前内存使用量除以 1024 的余数。
LUA_GCSTEP: 发起一步增量垃圾收集。步数由 data 控制(越大的值意味着越多步),而其具体含义(具体数字表示了多少)并未标准化。如果你想控制这个步数,必须实验性的测试 data 的值。如果这一步结束了一个垃圾收集周期,返回返回 1 。
LUA_GCSETPAUSE: 把 data/100 设置为 garbage-collector pause 的新值(参见 §2.10)。函数返回以前的值。
LUA_GCSETSTEPMUL: 把 arg/100 设置成 step multiplier (参见 §2.10)。函数返回以前的值。
lua_getallocf
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回给定状态机的内存分配器函数。如果 ud 不是 NULL ,Lua 把调用 lua_newstate 时传入的那个指针放入 *ud 。
lua_getfenv
void lua_getfenv (lua_State *L, int index);
把索引处值的环境表压入堆栈。
lua_getfield
void lua_getfield (lua_State *L, int index, const char *k);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值。在 Lua 中,这个函数可能触发对应 “index” 事件的元方法(参见 §2.8)。
lua_getglobal
void lua_getglobal (lua_State *L, const char *name);
把全局变量 name 里的值压入堆栈。这个是用一个宏定义出来的:
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, s)
lua_getmetatable
int lua_getmetatable (lua_State *L, int index);
- 1
- 2
- 3
- 4
- 5
把给定索引指向的值的元表压入堆栈。如果索引无效,或是这个值没有元表,函数将返回 0 并且不会向栈上压任何东西。
lua_gettable
void lua_gettable (lua_State *L, int index);
把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。
这个函数会弹出堆栈上的 key (把结果放在栈上相同位置)。在 Lua 中,这个函数可能触发对应 “index” 事件的元方法(参见 §2.8)。
lua_gettop
int lua_gettop (lua_State *L);
返回栈顶元素的索引。因为索引是从 1 开始编号的,所以这个结果等于堆栈上的元素个数(因此返回 0 表示堆栈为空)。
lua_insert
void lua_insert (lua_State *L, int index);
把栈顶元素插入指定的有效索引处,并依次移动这个索引之上的元素。不要用伪索引来调用这个函数,因为伪索引不是真正指向堆栈上的位置。
lua_Integer
typedef ptrdiff_t lua_Integer;
这个类型被用于 Lua API 接收整数值。
缺省时这个被定义为 ptrdiff_t ,这个东西通常是机器能处理的最大整数类型。
lua_isboolean
int lua_isboolean (lua_State *L, int index);
当给定索引的值类型为 boolean 时,返回 1 ,否则返回 0 。
lua_iscfunction
int lua_iscfunction (lua_State *L, int index);
当给定索引的值是一个 C 函数时,返回 1 ,否则返回 0 。
lua_isfunction
int lua_isfunction (lua_State *L, int index);
当给定索引的值是一个函数( C 或 Lua 函数均可)时,返回 1 ,否则返回 0 。
lua_islightuserdata
int lua_islightuserdata (lua_State *L, int index);
当给定索引的值是一个 light userdata 时,返回 1 ,否则返回 0 。
lua_isnil
int lua_isnil (lua_State *L, int index);
当给定索引的值是 nil 时,返回 1 ,否则返回 0 。
lua_isnumber
int lua_isnumber (lua_State *L, int index);
当给定索引的值是一个数字,或是一个可转换为数字的字符串时,返回 1 ,否则返回 0 。
lua_isstring
int lua_isstring (lua_State *L, int index);
当给定索引的值是一个字符串或是一个数字(数字总能转换成字符串)时,返回 1 ,否则返回 0 。
lua_istable
int lua_istable (lua_State *L, int index);
当给定索引的值是一个 table 时,返回 1 ,否则返回 0 。
lua_isthread
int lua_isthread (lua_State *L, int index);
当给定索引的值是一个 thread 时,返回 1 ,否则返回 0 。
lua_isuserdata
int lua_isuserdata (lua_State *L, int index);
当给定索引的值是一个 userdata (无论是完整的 userdata 还是 light userdata )时,返回 1 ,否则返回 0 。
lua_lessthan
int lua_lessthan (lua_State *L, int index1, int index2);
如果索引 index1 处的值小于索引 index2 处的值时,返回 1 ;否则返回 0 。其语义遵循 Lua 中的 < 操作符(就是说,有可能调用元方法)。如果任何一个索引无效,也会返回 0 。
lua_load
**int lua_load (lua_State *L,
lua_Reader reader,
void *data,
const char chunkname);*
加载一个 Lua chunk 。如果没有错误, lua_load 把一个编译好的 chunk 作为一个 Lua 函数压入堆栈。否则,压入出错信息。 lua_load 的返回值可以是:
0: 没有错误;
LUA_ERRSYNTAX: 在预编译时碰到语法错误;
LUA_ERRMEM: 内存分配错误。
- 1
- 2
- 3
- 4
这个函数仅仅加栽 chunk ;而不会去运行它。
lua_load 会自动检测 chunk 是文本的还是二进制的,然后做对应的加载操作(参见程序 luac)。
lua_load 函数使用一个用户提供的 reader 函数来读取 chunk (参见 lua_Reader)。 data 参数会被传入读取器函数。
chunkname 这个参数可以赋予 chunk 一个名字,这个名字被用于出错信息和调试信息(参见 §3.8)。
lua_newstate
lua_State *lua_newstate (lua_Alloc f, void *ud);
创建的一个新的独立的状态机。如果创建不了(因为内存问题)返回 NULL 。参数 f 是一个分配器函数; Lua 将通过这个函数做状态机内所有的内存分配操作。第二个参数 ud ,这个指针将在每次调用分配器时被直接传入。
lua_newtable
void lua_newtable (lua_State *L);
创建一个空 table ,并将之压入堆栈。它等价于 lua_createtable(L, 0, 0) 。
lua_newthread
lua_State *lua_newthread (lua_State *L);
创建一个新线程,并将其压入堆栈,并返回维护这个线程的 lua_State 指针。这个函数返回的新状态机共享原有状态机中的所有对象(比如一些 table),但是它有独立的执行堆栈。
没有显式的函数可以用来关闭或销毁掉一个线程。线程跟其它 Lua 对象一样是垃圾收集的条目之一。
lua_newuserdata
void *lua_newuserdata (lua_State *L, size_t size);
这个函数分配分配一块指定大小的内存块,把内存块地址作为一个完整的 userdata 压入堆栈,并返回这个地址。
userdata 代表 Lua 中的 C 值。完整的 userdata 代表一块内存。它是一个对象(就像 table 那样的对象):你必须创建它,它有着自己的元表,而且它在被回收时,可以被监测到。一个完整的 userdata 只和它自己相等(在等于的原生作用下)。
当 Lua 通过 gc 元方法回收一个完整的 userdata 时, Lua 调用这个元方法并把 userdata 标记为已终止。等到这个 userdata 再次被收集的时候,Lua 会释放掉相关的内存。
lua_next
int lua_next (lua_State *L, int index);
从栈上弹出一个 key(键),然后把索引指定的表中 key-value(健值)对压入堆栈(指定 key 后面的下一 (next) 对)。如果表中以无更多元素,那么 lua_next 将返回 0 (什么也不压入堆栈)。
典型的遍历方法是这样的:
/* table 放在索引 't' 处 */
lua_pushnil(L); /* 第一个 key */
while (lua_next(L, t) != 0) {
/* 用一下 'key' (在索引 -2 处) 和 'value' (在索引 -1 处) */
printf("%s - %s\n",
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
/* 移除 'value' ;保留 'key' 做下一次迭代 */
lua_pop(L, 1);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
在遍历一张表的时候,不要直接对 key 调用 lua_tolstring ,除非你知道这个 key 一定是一个字符串。调用 lua_tolstring 有可能改变给定索引位置的值;这会对下一次调用 lua_next 造成影响。
lua_Number
typedef double lua_Number;
Lua 中数字的类型。确省是 double ,但是你可以在 luaconf.h 中修改它。
通过修改配置文件你可以改变 Lua 让它操作其它数字类型(例如:float 或是 long )。
lua_objlen
size_t lua_objlen (lua_State *L, int index);
返回指定的索引处的值的长度。对于 string ,那就是字符串的长度;对于 table ,是取长度操作符 (‘#’) 的结果;对于 userdata ,就是为其分配的内存块的尺寸;对于其它值,为 0 。
lua_pcall
lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
以保护模式调用一个函数。
nargs 和 nresults 的含义与 lua_call 中的相同。如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。但是,如果有错误发生的话, lua_pcall 会捕获它,然后把单一的值(错误信息)压入堆栈,然后返回错误码。同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。
如果 errfunc 是 0 ,返回在栈顶的错误信息就和原始错误信息完全一致。否则,errfunc 就被当成是错误处理函数在栈上的索引。(在当前的实现里,这个索引不能是伪索引。)在发生运行时错误时,这个函数会被调用而参数就是错误信息。错误处理函数的返回值将被 lua_pcall 作为出错信息返回在堆栈上。
典型的用法中,错误处理函数被用来在出错信息上加上更多的调试信息,比如栈跟踪信息 (stack traceback) 。这些信息在 lua_pcall 返回后,因为栈已经展开 (unwound) ,所以收集不到了。
lua_pcall 函数在调用成功时返回 0 ,否则返回以下(定义在 lua.h 中的)错误代码中的一个:
LUA_ERRRUN: 运行时错误。
LUA_ERRMEM: 内存分配错误。对于这种错,Lua 调用不了错误处理函数。
LUA_ERRERR: 在运行错误处理函数时发生的错误。
- 1
- 2
- 3
lua_pop
void lua_pop (lua_State *L, int n);
从堆栈中弹出 n 个元素。
lua_pushboolean
void lua_pushboolean (lua_State *L, int b);
把 b 作为一个 boolean 值压入堆栈。
lua_pushcclosure
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一个新的 C closure 压入堆栈。
当创建了一个 C 函数后,你可以给它关联一些值,这样就是在创建一个 C closure (参见 §3.4);接下来无论函数何时被调用,这些值都可以被这个函数访问到。为了将一些值关联到一个 C 函数上,首先这些值需要先被压入堆栈(如果有多个值,第一个先压)。接下来调用 lua_pushcclosure 来创建出 closure 并把这个 C 函数压到堆栈上。参数 n 告之函数有多少个值需要关联到函数上。 lua_pushcclosure 也会把这些值从栈上弹出。
lua_pushcfunction
void lua_pushcfunction (lua_State *L, lua_CFunction f);
将一个 C 函数压入堆栈。这个函数接收一个 C 函数指针,并将一个类型为 function 的 Lua 值压入堆栈。当这个栈顶的值被调用时,将触发对应的 C 函数。
注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值(参见 lua_CFunction)。
lua_pushcfunction 是作为一个宏定义出现的:
#define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
lua_pushfstring
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
- 1
- 2
- 3
- 4
- 5
把一个格式化过的字符串压入堆栈,然后返回这个字符串的指针。它和 C 函数 sprintf 比较像,不过有一些重要的区别:
摸你需要为结果分配空间:其结果是一个 Lua 字符串,由 Lua 来关心其内存分配(同时通过垃圾收集来释放内存)。
这个转换非常的受限。不支持 flag ,宽度,或是指定精度。它只支持下面这些: '%%' (插入一个 '%'), '%s' (插入一个带零终止符的字符串,没有长度限制), '%f' (插入一个 lua_Number), '%p' (插入一个指针或是一个十六进制数), '%d' (插入一个 int), '%c' (把一个 int 作为一个字符插入)。
- 1
- 2
- 3
lua_pushinteger
void lua_pushinteger (lua_State *L, lua_Integer n);
把 n 作为一个数字压栈。
lua_pushlightuserdata
void lua_pushlightuserdata (lua_State *L, void *p);
把一个 light userdata 压栈。
userdata 在 Lua 中表示一个 C 值。 light userdata 表示一个指针。它是一个像数字一样的值:你不需要专门创建它,它也没有独立的 metatable ,而且也不会被收集(因为从来不需要创建)。只要表示的 C 地址相同,两个 light userdata 就相等。
lua_pushlstring
void lua_pushlstring (lua_State *L, const char *s, size_t len);
把指针 s 指向的长度为 len 的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串内可以保存有零字符。
lua_pushnil
void lua_pushnil (lua_State *L);
把一个 nil 压栈。
lua_pushnumber
void lua_pushnumber (lua_State *L, lua_Number n);
把一个数字 n 压栈。
lua_pushstring
void lua_pushstring (lua_State *L, const char *s);
把指针 s 指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝(或是复用一个拷贝),因此 s 处的内存在函数返回后,可以释放掉或是重用于其它用途。字符串中不能包含有零字符;第一个碰到的零字符会认为是字符串的结束。
lua_pushthread
int lua_pushthread (lua_State *L);
把 L 中提供的线程压栈。如果这个线程是当前状态机的主线程的话,返回 1 。
lua_pushvalue
void lua_pushvalue (lua_State *L, int index);
把堆栈上给定有效处索引处的元素作一个拷贝压栈。
lua_pushvfstring
const char *lua_pushvfstring (lua_State *L,
const char *fmt,
va_list argp);
- 1
- 2
- 3
- 4
- 5
等价于 lua_pushfstring,不过是用 va_list 接收参数,而不是用可变数量的实际参数。
lua_rawequal
int lua_rawequal (lua_State *L, int index1, int index2);
如果两个索引 index1 和 index2 处的值简单地相等(不调用元方法)则返回 1 。否则返回 0 。如果任何一个索引无效也返回 0 。
lua_rawget
void lua_rawget (lua_State *L, int index);
类似于 lua_gettable,但是作一次直接访问(不触发元方法)。
lua_rawgeti
void lua_rawgeti (lua_State *L, int index, int n);
把 t[n] 的值压栈,这里的 t 是指给定索引 index 处的一个值。这是一个直接访问;就是说,它不会触发元方法。
lua_rawset
void lua_rawset (lua_State *L, int index);
类似于 lua_settable,但是是作一个直接赋值(不触发元方法)。
lua_rawseti
void lua_rawseti (lua_State *L, int index, int n);
等价于 t[n] = v,这里的 t 是指给定索引 index 处的一个值,而 v 是栈顶的值。
函数将把这个值弹出栈。赋值操作是直接的;就是说,不会触发元方法。
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L,
void *data,
size_t *size);
- 1
- 2
- 3
lua_load 用到的读取器函数,每次它需要一块新的 chunk 的时候, lua_load 就调用读取器,每次都会传入一个参数 data 。读取器需要返回含有新的 chunk 的一块内存的指针,并把 size 设为这块内存的大小。内存块必须在下一次函数被调用之前一直存在。读取器可以通过返回一个 NULL 来指示 chunk 结束。读取器可能返回多个块,每个块可以有任意的大于零的尺寸。
lua_register
void lua_register (lua_State *L,
const char *name,
lua_CFunction f);
- 1
- 2
- 3
把 C 函数 f 设到全局变量 name 中。它通过一个宏定义:
#define lua_register(L,n,f) \
(lua_pushcfunction(L, f), lua_setglobal(L, n))
- 1
- 2
lua_remove
void lua_remove (lua_State *L, int index);
- 1
- 2
- 3
从给定有效索引处移除一个元素,把这个索引之上的所有元素移下来填补上这个空隙。不能用伪索引来调用这个函数,因为伪索引并不指向真实的栈上的位置。
lua_replace
void lua_replace (lua_State *L, int index);
把栈顶元素移动到给定位置(并且把这个栈顶元素弹出),不移动任何元素(因此在那个位置处的值被覆盖掉)。
lua_resume
int lua_resume (lua_State *L, int narg);
在给定线程中启动或继续一个 coroutine 。
要启动一个 coroutine 的话,首先你要创建一个新线程(参见 lua_newthread );然后把主函数和若干参数压到新线程的堆栈上;最后调用 lua_resume ,把 narg 设为参数的个数。这次调用会在 coroutine 挂起时或是结束运行后返回。当函数返回时,堆栈中会有传给 lua_yield 的所有值,或是主函数的所有返回值。如果 coroutine 切换时,lua_resume 返回 LUA_YIELD ,而当 coroutine 结束运行且没有任何错误时,返回 0 。如果有错则返回错误代码(参见 lua_pcall)。在发生错误的情况下,堆栈没有展开,因此你可以使用 debug API 来处理它。出错信息放在栈顶。要继续运行一个 coroutine 的话,你把需要传给 yield 作结果的返回值压入堆栈,然后调用 lua_resume 。
lua_setallocf
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
把指定状态机的分配器函数换成带上指针 ud 的 f 。
lua_setfenv
int lua_setfenv (lua_State *L, int index);
从堆栈上弹出一个 table 并把它设为指定索引处值的新环境。如果指定索引处的值即不是函数又不是线程或是 userdata , lua_setfenv 会返回 0 ,否则返回 1 。
lua_setfield
void lua_setfield (lua_State *L, int index, const char *k);
做一个等价于 t[k] = v 的操作,这里 t 是给出的有效索引 index 处的值,而 v 是栈顶的那个值。
这个函数将把这个值弹出堆栈。跟在 Lua 中一样,这个函数可能触发一个 “newindex” 事件的元方法(参见 §2.8)。
lua_setglobal
void lua_setglobal (lua_State *L, const char *name);
从堆栈上弹出一个值,并将其设到全局变量 name 中。它由一个宏定义出来:
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, s)
lua_setmetatable
int lua_setmetatable (lua_State *L, int index);
- 1
- 2
- 3
- 4
- 5
把一个 table 弹出堆栈,并将其设为给定索引处的值的 metatable 。
lua_settable
void lua_settable (lua_State *L, int index);
作一个等价于 t[k] = v 的操作,这里 t 是一个给定有效索引 index 处的值, v 指栈顶的值,而 k 是栈顶之下的那个值。
这个函数会把键和值都从堆栈中弹出。和在 Lua 中一样,这个函数可能触发 “newindex” 事件的元方法(参见 §2.8)。
lua_settop
void lua_settop (lua_State *L, int index);
参数允许传入任何可接受的索引以及 0 。它将把堆栈的栈顶设为这个索引。如果新的栈顶比原来的大,超出部分的新元素将被填为 nil 。如果 index 为 0 ,把栈上所有元素移除。
lua_State
typedef struct lua_State lua_State;
一个不透明的结构,它保存了整个 Lua 解释器的状态。 Lua 库是完全可重入的:它没有任何全局变量。(译注:从 C 语法上来说,也不尽然。例如,在 table 的实现中用了一个静态全局变量 dummynode_ ,但这在正确使用时并不影响可重入性。只是万一你错误链接了 lua 库,不小心在同一进程空间中存在两份 lua 库实现的代码的话,多份 dummynode_ 不同的地址会导致一些问题。)所有的信息都保存在这个结构中。
这个状态机的指针必须作为第一个参数传递给每一个库函数。 lua_newstate 是一个例外,这个函数会从头创建一个 Lua 状态机。
lua_status
int lua_status (lua_State *L);
返回线程 L 的状态。
正常的线程状态是 0 。当线程执行完毕或发生一个错误时,状态值是错误码。如果线程被挂起,状态为 LUA_YIELD 。
lua_toboolean
int lua_toboolean (lua_State *L, int index);
把指定的索引处的的 Lua 值转换为一个 C 中的 boolean 值( 0 或是 1 )。和 Lua 中做的所有测试一样, lua_toboolean 会把任何不同于 false 和 nil 的值当作 1 返回;否则就返回 0 。如果用一个无效索引去调用也会返回 0 。(如果你想只接收真正的 boolean 值,就需要使用 lua_isboolean 来测试值的类型。)
lua_tocfunction
lua_CFunction lua_tocfunction (lua_State *L, int index);
把给定索引处的 Lua 值转换为一个 C 函数。这个值必须是一个 C 函数;如果不是就返回 NULL 。
lua_tointeger
lua_Integer lua_tointeger (lua_State *L, int idx);
把给定索引处的 Lua 值转换为 lua_Integer 这样一个有符号整数类型。这个 Lua 值必须是一个数字或是一个可以转换为数字的字符串(参见 §2.2.1);否则,lua_tointeger 返回 0 。
如果数字不是一个整数,截断小数部分的方式没有被明确定义。
lua_tolstring
const char *lua_tolstring (lua_State *L, int index, size_t *len);
把给定索引处的 Lua 值转换为一个 C 字符串。如果 len 不为 NULL ,它还把字符串长度设到 *len 中。这个 Lua 值必须是一个字符串或是一个数字;否则返回返回 NULL 。如果值是一个数字,lua_tolstring 还会把堆栈中的那个值的实际类型转换为一个字符串。(当遍历一个表的时候,把 lua_tolstring 作用在键上,这个转换有可能导致 lua_next 弄错。)
lua_tolstring 返回 Lua 状态机中字符串的以对齐指针。这个字符串总能保证 ( C 要求的)最后一个字符为零 (‘\0’) ,而且它允许在字符串内包含多个这样的零。因为 Lua 中可能发生垃圾收集,所以不保证 lua_tolstring 返回的指针,在对应的值从堆栈中移除后依然有效。
lua_tonumber
lua_Number lua_tonumber (lua_State *L, int index);
把给定索引处的 Lua 值转换为 lua_Number 这样一个 C 类型(参见 lua_Number )。这个 Lua 值必须是一个数字或是一个可转换为数字的字符串(参见 §2.2.1 );否则,lua_tonumber 返回 0 。
lua_topointer
const void *lua_topointer (lua_State *L, int index);
把给定索引处的值转换为一般的 C 指针 (void*) 。这个值可以是一个 userdata ,table ,thread 或是一个 function ;否则,lua_topointer 返回 NULL 。不同的对象有不同的指针。不存在把指针再转回原有类型的方法。
这个函数通常只为产生 debug 信息用。
lua_tostring
const char *lua_tostring (lua_State *L, int index);
等价于 lua_tolstring ,而参数 len 设为 NULL 。
lua_tothread
lua_State *lua_tothread (lua_State *L, int index);
把给定索引处的值转换为一个 Lua 线程(由 lua_State* 代表)。这个值必须是一个线程;否则函数返回 NULL 。
lua_touserdata
void *lua_touserdata (lua_State *L, int index);
如果给定索引处的值是一个完整的 userdata ,函数返回内存块的地址。如果值是一个 light userdata ,那么就返回它表示的指针。否则,返回 NULL 。
lua_type
int lua_type (lua_State *L, int index);
返回给定索引处的值的类型,当索引无效时则返回 LUA_TNONE (那是指一个指向堆栈上的空位置的索引)。 lua_type 返回的类型是一些个在 lua.h 中定义的常量: LUA_TNIL , LUA_TNUMBER , LUA_TBOOLEAN , LUA_TSTRING , LUA_TTABLE , LUA_TFUNCTION , LUA_TUSERDATA , LUA_TTHREAD , LUA_TLIGHTUSERDATA 。
lua_typename
const char *lua_typename (lua_State *L, int tp);
返回 tp 表示的类型名,这个 tp 必须是 lua_type 可能返回的值中之一。
lua_Writer
typedef int (*lua_Writer) (lua_State *L,
const void* p,
size_t sz,
void* ud);
- 1
- 2
- 3
- 4
由 lua_dump 用到的写入器函数。每次 lua_dump 产生了一块新的 chunk ,它都会调用写入器。传入要写入的缓存 (p) 和它的尺寸 (sz) ,还有 lua_dump 的参数 data 。
写入器会返回一个错误码: 0 表示没有错误;别的值均表示一个错误,并且会让 lua_dump 停止再次调用写入器。
lua_xmove
void lua_xmove (lua_State *from, lua_State *to, int n);
传递 同一个 全局状态机下不同线程中的值。
这个函数会从 from 的堆栈中弹出 n 个值,然后把它们压入 to 的堆栈中。
lua_yield
int lua_yield (lua_State *L, int nresults);
切出一个 coroutine 。
这个函数只能在一个 C 函数的返回表达式中调用。如下:
return lua_yield (L, nresults);
- 1
- 2
当一个 C 函数这样调用 lua_yield ,正在运行中的 coroutine 将从运行中挂起,然后启动这个 coroutine 用的那次对 lua_resume 的调用就返回了。参数 nresults 指的是堆栈中需要返回的结果个数,这些返回值将被传递给 lua_resume 。
3.8 - 调试接口
Lua 没有内建的调试设施。取而代之的是提供了一些函数接口和钩子。利用这些接口,可以做出一些不同类型的调试器,性能分析器,或是其它一些需要从解释器中取到“内部信息”的工具。
lua_Debug
typedef struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) */
const char *what; /* (S) */
const char *source; /* (S) */
int currentline; /* (l) */
int nups; /* (u) upvalue 个数 */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
char short_src[LUA_IDSIZE]; /* (S) */
/* 私有部分 */
其它域 } lua_Debug;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
一个用来携带活动中函数的各种信息的结构。 lua_getstack 仅填写这个结构中的私有部分,这些部分以后会用到。调用 lua_getinfo 则可以填上 lua_Debug 中有用信息的那些域。
lua_Debug 中的各个域有下列含义:
source: 如果函数是定义在一个字符串中,source 就是这个字符串。如果函数定义在一个文件中, source 是一个以 '@' 开头的文件名。
short_src: 一个“可打印版本”的 source,用于出错信息。
linedefined: 函数定义开始处的行号。
lastlinedefined: 函数定义结束处的行号。
what: 如果函数是一个 Lua 函数,则为一个字符串 "Lua" ;如果是一个 C 函数,则为 "C";如果它是一个 chunk 的主体部分,则为 "main";如果是一个作了尾调用的函数,则为 "tail" 。别的情况下,Lua 没有关于函数的别的信息。
currentline: 给定函数正在执行的那一行。当提供不了行号信息的时候,currentline 被设为 -1 。
name: 给定函数的一个合理的名字。因为 Lua 中的函数也是一个值,所以它们没有固定的名字:一些函数可能是全局复合变量的值,另一些可能仅仅只是被保存在一个 table 中。 lua_getinfo 函数会检查函数是这样被调用的,以此来找到一个适合的名字。如果它找不到名字,name 就被设置为 NULL 。
namewhat: 结实 name 域。 namewhat 的值可以是 "global", "local", "method", "field", "upvalue", 或是 "" (空串)。这取决于函数怎样被调用。(Lua 用空串表示其它选项都不符合)
nups: 函数的 upvalue 的个数。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
lua_gethook
lua_Hook lua_gethook (lua_State *L);
返回当前的钩子函数。
lua_gethookcount
int lua_gethookcount (lua_State *L);
返回当前钩子记数。
lua_gethookmask
int lua_gethookmask (lua_State *L);
返回当前的钩子掩码 (mask) 。
lua_getinfo
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
返回一个指定的函数或函数调用的信息。
当用于取得一次函数调用的信息时,参数 ar 必须是一个有效的活动的记录。这条记录可以是前一次调用 lua_getstack 得到的,或是一个钩子 (参见 lua_Hook)得到的参数。
用于获取一个函数的信息时,可以把这个函数压入堆栈,然后把 what 字符串以字符 ‘>’ 起头。(这个情况下,lua_getinfo 从栈顶上弹出函数。) 例如,想知道函数 f 在哪一行定义的,你可以下下列代码:
lua_Debug ar;
lua_getfield(L, LUA_GLOBALSINDEX, "f"); /* 取到全局变量 'f' */
lua_getinfo(L, ">S", &ar);
printf("%d\n", ar.linedefined);
- 1
- 2
- 3
- 4
what 字符串中的每个字符都筛选出结构 ar 结构中一些域用于填充,或是把一个值压入堆栈:
'n': 填充 name 及 namewhat 域;
'S': 填充 source, short_src, linedefined, lastlinedefined,以及 what 域;
'l': 填充 currentline 域;
'u': 填充 nups 域;
'f': 把正在运行中指定级别处函数压入堆栈;(译注:一般用于获取函数调用中的信息,级别是由 ar 中的私有部分来提供。如果用于获取静态函数,那么就直接把指定函数重新压回堆栈,但这样做通常无甚意义。)
'L': 压一个 table 入栈,这个 table 中的整数索引用于描述函数中哪些行是有效行。(有效行指有实际代码的行,即你可以置入断点的行。无效行包括空行和只有注释的行。)
- 1
- 2
- 3
- 4
- 5
- 6
这个函数出错会返回 0 (例如,what 中有一个无效选项)。
lua_getlocal
const char *lua_getlocal (lua_State *L, lua_Debug *ar, int n);
- 1
从给定活动记录中获取一个局部变量的信息。参数 ar 必须是一个有效的活动的记录。这条记录可以是前一次调用 lua_getstack 得到的,或是一个钩子 (参见 lua_Hook)得到的参数。索引 n 用于选择要检阅哪个局部变量( 1 表示第一个参数或是激活的第一个局部变量,以此类推,直到最后一个局部变量)。 lua_getlocal 把变量的值压入堆栈并返回它的名字。
以 ‘(’ (正小括号)开始的变量指内部变量(循环控制变量,临时变量,C 函数局部变量)。
当索引大于局部变量的个数时,返回 NULL (什么也不压入)。
lua_getstack
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
获取解释器的运行时栈的信息。
这个函数用正在运行中的给定级别处的函数的活动记录来填写 lua_Debug 结构的一部分。 0 级表示当前运行的函数,而 n+1 级处的函数就是调用第 n 级函数的那一个。如果没有错误,lua_getstack 返回 1 ;当调用传入的级别大于堆栈深度的时候,返回 0 。
lua_getupvalue
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
获取一个 closure 的 upvalue 信息。(对于 Lua 函数,upvalue 是函数需要使用的外部局部变量,因此这些变量被包含在 closure 中。) lua_getupvalue 获取第 n 个 upvalue ,把这个 upvalue 的值压入堆栈,并且返回它的名字。 funcindex 指向堆栈上 closure 的位置。( 因为 upvalue 在整个函数中都有效,所以它们没有特别的次序。因此,它们以字母次序来编号。)
当索引号比 upvalue 数量大的时候,返回 NULL (而且不会压入任何东西)对于 C 函数,这个函数用空串 “” 表示所有 upvalue 的名字。
lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
用于调试的钩子函数类型。
无论何时钩子被调用,它的参数 ar 中的 event 域都被设为触发钩子的事件。 Lua 把这些事件定义为以下常量: LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILRET, LUA_HOOKLINE, and LUA_HOOKCOUNT。除此之外,对于 line 事件,currentline 域也被设置。要想获得 ar 中的其他域,钩子必须调用 lua_getinfo。对于返回事件,event 的正常值可能是 LUA_HOOKRET,或者是 LUA_HOOKTAILRET 。对于后一种情况,Lua 会对一个函数做的尾调用也模拟出一个返回事件出来;对于这个模拟的返回事件,调用 lua_getinfo 没有什么作用。
当 Lua 运行在一个钩子内部时,它将屏蔽掉其它对钩子的调用。也就是说,如果一个钩子函数内再调回 Lua 来执行一个函数或是一个 chunk ,这个执行操作不会触发任何的钩子。
lua_sethook
int lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
设置一个调试用钩子函数。
参数 f 是钩子函数。 mask 指定在哪些事件时会调用:它由下列一组位常量构成 LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE,以及 LUA_MASKCOUNT。参数 count 只在 mask 中包含有 LUA_MASKCOUNT 才有意义。对于每个事件,钩子被调用的情况解释如下:
call hook: 在解释器调用一个函数时被调用。钩子将于 Lua 进入一个新函数后,函数获取参数前被调用。
return hook: 在解释器从一个函数中返回时调用。钩子将于 Lua 离开函数之前的那一刻被调用。你无权访问被函数返回出去的那些值。 (译注:原文 (You have no access to the values to be returned by the function) 如此。但“无权访问”一词值得商榷。某些情况下你可以访问到一些被命名为 (*temporary) 的局部变量,那些索引被排在最后的 (*temporary) 变量指的就是返回值。但是由于 Lua 对特殊情况做了一些优化,比如直接返回一个被命名的局部变量,那么就找不到对应的 (*temporary) 变量了。本质上,返回值一定存在于此刻的局部变量中,并且可以访问它,只是无法确定是哪些罢了。至于这个时候函数体内的其它局部变量,是不保证有效的。进入 return hook 的那一刻起,实际已经退出函数内部的运行环节,返回值占用的局部变量空间以后的部分,都有可能因 hook 本身复用它们而改变。)
line hook: 在解释器准备开始执行新的一行代码时,或是跳转到这行代码中时(即使在同一行内跳转)被调用。(这个事件仅仅在 Lua 执行一个 Lua 函数时发生。)
count hook: 在解释器每执行 count 条指令后被调用。(这个事件仅仅在 Lua 执行一个 Lua 函数时发生。)
钩子可以通过设置 mask 为零屏蔽。
- 1
- 2
- 3
- 4
- 5
- 6
lua_setlocal
const char *lua_setlocal (lua_State *L, lua_Debug *ar, int n);
设置给定活动记录中的局部变量的值。参数 ar 与 n 和 lua_getlocal 中的一样(参见 lua_getlocal)。 lua_setlocal 把栈顶的值赋给变量然后返回变量的名字。它会将值从栈顶弹出。
当索引大于局部变量的个数时,返回 NULL (什么也不弹出)。
lua_setupvalue
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
设置 closure 的 upvalue 的值。它把栈顶的值弹出并赋于 upvalue 并返回 upvalue 的名字。参数 funcindex 与 n 和 lua_getupvalue 中的一样(参见 lua_getupvalue)。
当索引大于 upvalue 的个数时,返回 NULL (什么也不弹出)。
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
</div>