Lua 数据类型
nil 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean 包含两个值:false和true。
number 表示双精度类型的实浮点数
function 由 C 或 Lua 编写的函数
string 字符串由一对双引号或单引号来表示
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。
userdata 表示任意存储在变量中的C数据结构
nil类型
对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉,
tab1 = { key1 = "val1", key2 = "val2", "val3" }for k, v in pairs(tab1) do
print(k .. " - " .. v)end
tab1.key1 = nilfor k, v in pairs(tab1) do
print(k .. " - " .. v)end
boolean类型
boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是"假",其他的都为"真":
number类型
Lua 默认只有一种 number 类型 -- double(双精度)类型
string类型
也可以用 2 个方括号 "[[]]" 来表示"一块"字符串。
html = [[
http://www.w3cschool.cc/">w3cschool菜鸟教程
]]
print(html)
打印结果为
http://www.w3cschool.cc/">w3cschool菜鸟教程
在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字:
使用 # 来计算字符串的长度,放在字符串前面,如下实例:
table(表)
对table的索引可以使用[].有些情况下也可以使用.操作
t[i]
t.i 仅当索引是字符串类型时可以使用
table一般完整写法
local a = {["x"] = 12, ["mutou"] = 99, [3] = "hello"}
print(a["x"]);
对于字符串下标,我们可以省略方框和双引号,但是数字下标不可以
local a = {x = 12, mutou = 99, [3] = "hello"}
print(a.x);
大家习惯了数组,用数字下标
local a = {[1] = 12, [2] = 43, [3] = 45, [4] = 90}
gettable_event(t,i) 采用索引本质上是方法的调用
userdata(自字义内容)
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。
Lua 变量
lua中的变量有3种,全局变量,局部变量和表中的域
函数外的变量默认为全局变量,除非用local声明,函数内变量和函数参数默认为局部变量
-- test.lua 文件脚本a = 5 -- 全局变量local b = 5 -- 局部变量function joke() c = 5 -- 局部变量 local d = 6 -- 局部变量endprint(c,d) --> nil nildo local a = 6 -- 局部变量 b = 6 -- 全局变量 print(a,b); --> 6 6endprint(a,b) --> 5 6
lua中可以通过以下方式交换俩个变量的值(lua可以对多个变量赋值,变量列表和值例表用,隔开)
x,y = y,x
当变量个数和值不一致时,lua采取以变量个数为准的策略
a. 变量个数 > 值的个数 按变量个数补足nil b. 变量个数 < 值的个数 多余的值会被忽略
Lua 循环
while循环 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for循环 重复执行指定语句,重复次数可在 for 语句中控制。
lua repeat...util循环 重复执行循环,直到 指定的条件为真时为止
Lua 字符串
lua提供了很多字符串操作
string.upper(argument) 字符串全部转为大写字母
string.lower(argument); 字符串全部转换成小写字母
string.gsub(mainstring,findstring,replacestring,num) mainstrig中的findstring都转换成replacestring,num表示转换几次
string.strfind(str,substr,[init,[end]]) 在一个指定的字符串中搜索指定的内容,返回开始位置和终止位置,第三个参数为可选参数表示init起始位置 ,end不知道
string.reverse(arg) 反转字符串
string.fomat() 返回一个类似print的字符串,
str = string.format("the value is %d",3)
print(str)
string.char(arg) string.byte(arg,[init]) 根据ascii码转换 char转换数字为字符 byte转换字符为数字 init表示从哪个位置开始
string.len(arg) 计算字符串的长度,也可以通过#运算符来取得
string.rep(arg,n) 返回字符串的n个拷贝
多维数组
初始化
array = {} for i = 1,3 do array[i] = {} for j = 1,3 do array[i][j] = 8 end end
Table 操作
table.concat(table[sep,[,start,[,end]]]) table.concat参数中指定table的数组部分从start位置到end位置的所有元素,元素间以指定的分割符sep隔开
fruits = {"banana","orange","apple"} -- 返回 table 连接后的字符串 print("连接后的字符串 ",table.concat(fruits)) -- 指定连接字符 print("连接后的字符串 ",table.concat(fruits,", ")) -- 指定索引来连接 tableprint("连接后的字符串 ",table.concat(fruits,", ", 2,3))
table.insert(table,[pos],value) 插入元素,无pos参数插入最后
table.remove(table,[pos]) 删除元素,无pos参数删除最后
fruits = {"banana","orange","apple"} -- 在末尾插入table.insert(fruits,"mango") print("索引为 4 的元素为 ",fruits[4]) -- 在索引为 2 的键处插入 table.insert(fruits,2,"grapes")print("索引为 2 的元素为 ",fruits[2]) print("最后一个元素为 ",fruits[5])table.remove(fruits) print("移除后最后一个元素为 ",fruits[5]) --这人为nil
table.sort(table,[comp]) 按升序排列
fruits = {"banana","orange","apple","grapes"} print("排序前") for k,v in ipairs(fruits) do print(k,v) endtable. sort(fruits) print("排序后") for k,v in ipairs(fruits) do print(k,v) end
Lua 模块与包(其实是table)
模块相当于封闭库,可以将一些公用的代码放到这个里面,以Api接口的形式在其它地方调用,有利于代码的重用和降低耦合度
模块是由变量,函数等组成的Table,因些创建一个模块很简单,就是创建一个Table,然后把需要导入的常量,函数放入其中,最后返回table
--定义一个model模块,注意文件名也必须是model modul = {} modul.constant = "constnum" function modul.fun1() print("public function") end function fun2() print("prive function") end function modul.fun3() fun2() end return modul
由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。
上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.
require("modul") print(modul.constant) modul.fun1() --modul.fun2() 错误,私有的 modul.fun3()
加载机制
对于自定义的模块,模块文件不是放在哪个目录都行的,函数require有它自己的路径加载策略,它会尝试从lua或者C库中加载模块
reuire用于尝试搜索lua文件的路径是存放在package.path中,它lua启动后会通过LUA_PATH的值来初始这个环境变量,如果没有找到,则会默认一个路径来初始化
当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 "~/lua/" 路径加入 LUA_PATH 环境变量里:
#LUA_PATH export LUA_PATH="~/lua/?.lua;;"
文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。
接着,更新环境变量参数,使之立即生效。
source ~/.profile
这时假设 package.path 的值是:
/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua
那么调用 require("module") 时就会尝试打开以下文件目录去搜索目标。
/Users/dengjoe/lua/module.lua; ./module.lua /usr/local/share/lua/5.1/module.lua /usr/local/share/lua/5.1/module/init.lua /usr/local/lib/lua/5.1/module.lua /usr/local/lib/lua/5.1/module/init.lua
C 包
Lua和C是很容易结合的,使用C为Lua写包。
与Lua中写包不同,C包在使用以前必须首先加载并连接,在大多数系统中最容易的实现方式是通过动态连接库机制。
Lua在一个叫loadlib的函数内提供了所有的动态连接的功能。这个函数有两个参数:库的绝对路径和初始化函数。所以典型的调用的例子如下:
local path = "/usr/local/lua/lib/libluasocket.so" local f = loadlib(path, "luaopen_socket")
loadlib函数加载指定的库并且连接到Lua,然而它并不打开库(也就是说没有调用初始化函数),反之他返回初始化函数作为Lua的一个函数,这样我们就可以直接在Lua中调用他。
如果加载动态库或者查找初始化函数时出错,loadlib将返回nil和错误信息。我们可以修改前面一段代码,使其检测错误然后调用初始化函数:
local path = "/usr/local/lua/lib/libluasocket.so" -- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下 local f = assert(loadlib(path, "luaopen_socket")) f() -- 真正打开库
一般情况下我们期望二进制的发布库包含一个与前面代码段相似的stub文件,安装二进制库的时候可以随便放在某个目录,只需要修改stub文件对应二进制库的实际路径即可。
将stub文件所在的目录加入到LUA_PATH,这样设定后就可以使用require函数加载C库了。
Lua 元表(Metatable)
lua中Table我们可以通过key来得到Value,但是无法对俩个表进行操作
因此lua提供了元表(metatable)允许我们改变Table的行为,每个行为关联对应的元方法
例如使用元表我们可以定义lua如何计算两个Talble相加操作a+b,当lua试图对俩个表相加时,先检查两者之一是否有元表,之后检查是否有_add的字段,若找到则调用对应的值
"_add"等即时字段,其对应的值(往往是一个函数或者table)就是"元方法"
两个重要的方法来处理元表
setmetatable(table,metatable)给指定table设定元表(metatable),如果元表中存在__metatable建值,失败
getmetatable(table)返回对像的元表
mytable = {} -- 普通表 mymetatable = {} -- 元表 setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
以上代码可以写成一行
mytable = setmetatable({},{})
以下返回对像元素
getmetatable(mytable) -- 这回返回mymetatable
__index元方法
这是metatable最常用的键
当你通过键来访问table的时候,如果这个键没有值,那么lua会寻找table的metatable(假定有metatable)中的__index键,
如果__index包含一个函数的话,lua就会调用这个函数,table和键会作为参数传递给函数
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
分析mytable表赋值{key1 = "value1"}
mytable设置元表,元方法为__index
在mytable表中查找key1,如果找到,返回该元素,找不到继续
在mytable表中查找 key2,如果找到,返回 metatablevalue,找不到则继续。
判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数。
元方法中查看是否传入 "key2" 键的参数(mytable.key2已设置),如果传入 "key2" 参数返回 "metatablevalue",否则返回 mytable 对应的键值。