$ sudo apt-get install lua5.2
$ brew install lua luarocks # luarocks是lua的模块管理工具 $ sudo ln -s /usr/bin/make /usr/bin/gmake # 解决 sh: gmake: command not found
$ luarocks install luasocket $ lua > socket = require("socket") > print(socket._VERSION) LuaSocket 2.0.2
$ luarocks install lua-cjson $ lua > cjson = require("cjson") > print(cjson.encode({ name = "linguofeng" })) {"name":"linguofeng"}
$ lua > print("Hello World!!")
Hello World!!
print(type(nil)) -- 输出 nil print(type(99.7+12*9)) -- 输出 number print(type(true)) -- 输出 boolean print(type("Hello Wikipedia")) -- 输出 string print(type(print)) -- 输出 function print(type{1, 2, test = "test"}) -- 输出 table
第一类值指:在Lua中函数和其他值(数值、字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值。
function add(x, y) -- 定义一个函数add,并接收两个参数 local a = x + y -- 定义一个局部变量a,接收x+y的和,局部变量仅在函数add中有效 return a -- 返回 end -- 结束add函数 print("15 + 64 = " .. add(15, 64)); -- 打印add(15, 64)的结果 local x = 1 -- local 关键字表示该变量为局部变量,作用域为当前上下文 -- 无该关键字修饰时为全局变量,作用于整个Lua状态机 local add = function(x, y) -- 局部函数,作用于当前脚本(chumk) Lib = {} Lib.add = function(x, y) -- 表函数,作用于Lib表
闭包是一个内部函数以及它的upvalues,内部函数使用了外部(父函数)局部变量。
function newCounter() local i = 0 -- i为匿名函数的外部局部变量(upvalue) return function() -- 匿名内部函数 i = i + 1 -- 使用了i,所以该匿名函数是一个闭包 return i end end c1 = newCounter() -- 得到一个匿名函数的变量(闭包) print(c1()) -- 调用匿名函数,打印出1 print(c1()) -- 调用匿名函数,打印出2 c2 = newCounter() print(c2()) --> 1 print(c1()) --> 3 print(c2()) --> 2
for int i = 0, 10, 2 do -- for循环,2表示步长,省略时为1 print("i = " .. i) -- .. 表示字符串连接符 end -- 结束for if a > b then -- if条件判断语句 print("a > b") else print("b > a") end while a > b do -- while循环 print("") end repeat -- repeat-until循环 print("") until a > b
逻辑运算符认为false和nil是假(false),其他为真,0也是true.
a and b -- 如果a为false,则返回a,否则返回b a or b -- 如果a为true,则返回a,否则返回b x = x or v -- 如果x为false或者nil时则给x赋初始值v -- 等价于 if not x then x = v end -- 三元运算符 a ? b : c => a and b or c -- and 的优先级别比 or 高 not -- not 的结果只返回false或true,作用类似于"非" "!"取反的意思 print(not nil) -- true print(not false) -- true print(not 0) -- false
co = coroutine.create(function () -- 创建一个协同函数,接收一个匿名函数,返回thread类型 print("hi") end) print(co) -- thread: 0x7fe1834127d0
print(coroutine.status(co)) -- 查看协同的状态,默认状态是挂起态 suspended coroutine.resume(co) -- 改变协同的状态为运行太 hi print(coroutine.status(co)) -- 协同运行完以后将变量停止态 dead
co = coroutine.create(function () print("hi") coroutine.yield() -- 协同运行到此状态将变成挂起 print("你好") end) coroutine.resume(co) -- hi coroutine.resume(co) -- 你好 coroutine.resume(co) -- false,协同结束后将不能再使用
co = coroutine.create(function (x, y) -- 接收两个参数 print("hi", coroutine.yield(x + y)) -- 返回一个值,同时参数也传递给了coroutine.yield return 100 -- 第三种返回值的方式 end) print(coroutine.resume(co, 12, 87)) -- 传递两个参数并接收返回值(true, 99) -- 执行coroutine.yield(x + y)之前协同被挂起,但值被返回,因此print函数未被执行,下面执行 print(coroutine.resume(co, 12, 87)) -- 传递两个参数并接收返回值(true, 100)
arrays = {} -- 创建一个空表 arrays[1] = "abc" -- 第一个索引值为1 arrays[2] = 123 arrays["key"] = "value" -- map for key, value in pairs(arrays) do -- 迭代table print(key .. " = " .. value) end
list = {123} -- 初始化表 list[2] = "abc" -- 增 list.x = 123 list.y = 987 list[1] = nil -- 删 list.y = nil list[2] = 456 -- 改 list.x = 987 print(list[2]) -- 查 print(list.x) print(list['x'])
list = {} -- 初始空化数组,数组的下标是整数,遵循Lua的标准,下标从1开始 list[1] = "abc" list[2] = "edg" list[3] = "hij"
mt = {} -- 创建矩阵matrix for i = 1, N do -- 创建N行 mt[i] = {} -- 每行都是一个数组(table元素) for j = 1, M do -- 创建M列 mt[i][j] = "a" -- 第N行第M行的值 end end
list = nil list = {next = list, value = "hello3"} list = {next = list, value = "hello2"} list = {next = list, value = "hello1"} -- 遍历 local l = list while l do print(l.value) l = l.next end
元表也是普通表
t = {} print(getmetatable(t)) -- 获取表的metatable nil,默认不带 mt = {} setmetatable(t, mt) -- 设置一个元素 -- metamethod 元表的方法(元方法) mt.__add -- 加 + mt.__sub -- 减 - mt.__mul -- 乘 * mt.__div -- 除 / mt.__unm -- 负 - mt.__pow -- 幂 ^ mt.__concat -- 连接 mt.__eq -- 等于 = mt.__lt -- 小于 < mt.__le -- 大于 > mt.__tostring -- print调用 mt.__metatable -- 设置该元表不被修改与访问 mt.__index -- 当访问不存在的元素时会去查询,相当于子类继承父类一样 mt.__newindex -- 更新表,如果增加一个不存在的元素,会去查询,有直接用,否则增加
记录下表的增查记录
local index = {} -- 私有的key,用来记录原始表在代理表中的下标 local mt = { -- 创建元表 __index = function(t, k) print("访问了" .. tostring(k) .. "元素") return t[index][k] -- 从代理表中获取原始表中k下标的数据 end, __newindex = function(t, k, v) print("更新了 " .. tostring(k) .. " 元素的值为 " .. tostring(v)) t[index][k] = v -- 更新代理表中下标为index的原始表中的元素 end } function setProxy(t) local proxy = {} -- 创建代理表 proxy[index] = t -- 把原始表加到代理表的index下标中 setmetatable(proxy, mt) -- 设置代理表的元表 return proxy -- 返回代理表,即所有操作都是直接操作代理表 end p = setProxy({}) p[2] = 'abcdefg' -- 更新了 2 元素的值为 abcdefg print(p[2]) -- 访问了2元素
> _G["ewgegw"] = "ddddddgege" > table.foreach(_G, print) string table: 0x7ffce3407a60 xpcall function: 0x7ffce3404780 package table: 0x7ffce3405780 tostring function: 0x7ffce3405020 print function: 0x7ffce3405160 os table: 0x7ffce34073e0 unpack function: 0x7ffce34050d0 ewgegw ddddddgege -- 上面添加的全局变量 require function: 0x7ffce3405e70 getfenv function: 0x7ffce3404db0 setmetatable function: 0x7ffce3404f60 next function: 0x7ffce3404d20 assert function: 0x7ffce3404a80 tonumber function: 0x7ffce3404fc0 io table: 0x7ffce3406bd0 rawequal function: 0x7ffce34051b0 collectgarbage function: 0x7ffce3404ad0 getmetatable function: 0x7ffce3404e00 module function: 0x7ffce3405e20 rawset function: 0x7ffce3405260 math table: 0x7ffce3408290 debug table: 0x7ffce3408c50 pcall function: 0x7ffce3404d70 table table: 0x7ffce3405f10 newproxy function: 0x7ffce34052e0 type function: 0x7ffce3405080 coroutine table: 0x7ffce3405380 -- 对应的是协同的表 _G table: 0x7ffce3404110 select function: 0x7ffce3404ec0 gcinfo function: 0x7ffce3404150 pairs function: 0x7ffce34048c0 rawget function: 0x7ffce3405210 loadstring function: 0x7ffce3404cc0 ipairs function: 0x7ffce3404830 _VERSION Lua 5.1 dofile function: 0x7ffce3404bd0 setfenv function: 0x7ffce3404f10 load function: 0x7ffce3404c70 error function: 0x7ffce3404c20 loadfile function: 0x7ffce3404e60 > table.foreach(_G.os, print)
--pack.lua--------------------------------------------------------------------- local P = {} -- 改变P表的__index,这里的_G代表全局环境 setmetatable(P, {__index = _G}) -- 改变当前的环境为P,setfenv前的所有定义都是在全局环境中进行的,后面的则都是在新环境中进行的,互不影响 setfenv(1, P) -- 声明的add函数在环境P中,如果要在外部访问必须P.add function add(x, y) print(x .. ' + ' .. y .. ' = ' .. (x + y)) -- 由于当前新的环境中没有print函数,但是__index指向的是全局环境,所以print是全局的函数 end return P --pack1.lua-------------------------------------------------------------------- local P = {} -- 如果需要改变环境后使用全局环境的方法需要记住,这种方法比上面的要快 local print = print -- 改变当前的环境为P setfenv(1, P) -- 声明的add函数在环境P中,如果要在外部访问必须P.add function add(x, y) print(x .. ' + ' .. y .. ' = ' .. (x + y)) end -- 私有方法 local function div(x, y) end return P --main.lua--------------------------------------------------------------------- local p = require 'pack' p.add(12, 34) local p1 = require 'pack1' p1.add(43, 19)
-- student.lua student = {} function student.sayHi() print('Hello') end return student -- 使用 student = require("student") student.sayHi() -- Hello
local function _add(x, y) -- 私有局部函数 return x + y end utils = { -- utils包 add = _add -- 对外公开的函数 } return utils
--Person.lua local Person = {name = ''} function Person:getName() return self.name end function Person:setName(name) self.name = name end function Person:new(object) object = object or {} setmetatable(object, {__index = self}) -- 元表 类似继承的意思 return object end return Person --main.lua -- 类 local Person = require 'Person' -- 对象 local student = Person:new({age = 23}) student:setName('Tom') print('name: ' .. student:getName() .. ' age: ' .. student.age)
实际就是记住所有父类,然后访问不存在的元素的时候去查询哪个父类中有,有就执行
local function search (k, plist) for i=1, table.getn(plist) do local v = plist[i][k] -- 去所有父类中获取 if v then return v end end end function Person:new(...) local o = {} setmetatable(o, {__index = function (t, k) local v = search(k, arg) t[k] = v -- save for next access return v end}) return o end
local function createAccount(_name) -- 工厂方法 local self = {name = _name} local function _setName(name) self.name = name end local function _getName() return self.name end -- 公有方法表 local public = { setName = _setName, getName = _getName, --name = self.name -- 不公开私有成员变量 } return public end local account = createAccount('Tom') print(account.name) -- 无法访问,因为没有公开
t = {name = 'table'} -- 创建一个普通表 setmatetable(t, {__made = 'k'}) -- k表示t表中的keys是weak的,v表示t表中的values是weak的 k = {} -- 创建一个空表,此时{}被k引用,引用值为1 t[k] = 1 -- 把空表作为key,由于t表的key是weak的,所以k值的引用如果为0则会被gc回收,如 k = {} -- 把k指向另一个新的{},则旧的{}引用值减1变成0了,目前t[k] = 1还有效 t[k] = 2 -- 把新的{}作为key,值是2 collectgarbage() -- 调用gc,清除引用为0的内存空间,此时,第一个{}的引用是0,会被gc掉,所以第一个t[k]以及值会被删除 for k, v in pairs(a) do print(v) end -- 此时应该只剩下2了,因为第2个k = {}时改变了k指向新的{},而旧的{}引用会变成0,被gc掉 ------------------------------------------------------------------------- a = {}; setmetatable(a, {__mode = 'v'}); -- values为weak,当值的引用为0时,删除 v1 = {name = 'v1'} v2 = {name = 'v2'} a[1] = v1 a[2] = v2 v1 = v2 collectgarbage(); -- 调用GC,清掉weak表中没有引用的内存 for k, v in pairs(a) do print(v.name) end -- 输出v2,因为v1重新指向{name = 'v2'},则{name = 'v1'}引用减1为0 ------------------------------------------------------------------------- a = {}; setmetatable(a, {__mode = 'kv'}); -- 同时检查kv,是上面两种情况的组合 v1 = {name = 'v1'} v2 = {name = 'v2'} v = {} k = {} a[1] = v v = {} -- value重新引用新值,旧值被gc,如果旧值在table则对应的记录被清空 a[2] = v a[k] = 1 k = {} -- key重新引用新值,旧值被gc,如果旧值在table则对应的记录被清空 a[k] = 2 collectgarbage(); -- 调用GC,清掉weak表中没有引用的内存 for k, v in pairs(a) do print(v) end
tables = {1, 2, 3, 4, 5, 6, 7} print(#tables) -- 5.1开始使用#获取长度 -- 7 table.insert(tables, 8) print(table.concat(tables)) -- 12345678 table.insert(tables, 1, 0) print(table.concat(tables)) -- 012345678 print(table.maxn(tables)) -- 9 table.remove(tables) print(table.concat(tables)) -- 01234567 table.remove(tables, 5) print(table.concat(tables)) -- 0123567 print(table.concat(tables, ',')) -- 0,1,2,3,5,6,7 print(table.concat(tables, '-', 2)) -- 1-2-3-5-6-7 print(table.concat(tables, '=', 1, 4)) -- 0=1=2=3 table.sort(tables) print(table.concat(tables)) -- 0123567 table.sort(tables, function(t1, t2) if t1 > t2 then return true else return false end end) print(table.concat(tables)) -- 7653210
local file = io.open('tabletest.lua', 'r') print(io.type(file)) for line in file:lines() do --print(line) end --file:close() io.close(file) print(io.type(file)) ------------------------------------------------------ for line in io.input('tabletest.lua'):lines() do print(line) end for line in io.lines('tabletest.lua') do --print(line) end
table.foreach(os, print) print(os.clock()) print(os.date()) print(os.date('%Y-%m-%d %H:%M')) print(os.time()) print(os.difftime(1364957757, os.time())) print(os.getenv ('PATH')) print(os.tmpname ())
@压入@
table(table table-bordered). |_.函数|_.说明(栈底最后一个元素的索引是1,栈顶第一个元素是-1)| |lua_pushnil(lua_State*)|压入一个空值| |lua_pushboolean(lua_State*, int)|压入一个布尔值| |lua_pushcclosure(lua_State*, lua_CFunction, int)|压入一个C闭包?| |lua_pushcfunction(lua_State*, lua_CFunction)|压入一个C函数,由lua_pushcclosure(L, f, 0)宏定义出来| |lua_pushlightuserdata(lua_State*, void*)|压入一个指针,不被gc管理| |lua_pushinteger(lua_State*, lua_Integer)|压入一个数字| |lua_pushnumber(lua_State*, lua_Number)|压入数字| |lua_pushstring(lua_State*, const char*)|压入字符串| |lua_pushfstring(lua_State*, const char*, ...)|压入一个格式化的string| |lua_pushvfstring(lua_State*, const char*, va_list)|同上,只是接收一个va_list| |lua_pushlstring(lua_State*, const char*, size_t);|压入长字符串| |lua_pushliteral(lua_State*, const char*)|压入文字| |lua_pushthread(lua_State*)|压入一个线程?|@判断类型@
table(table table-bordered). |_.函数|_.说明| |lua_isboolean(lua_State*, int)|是否是布尔类型| |lua_iscfunction(lua_State*, int)|是否是C函数类型| |lua_isfunction(lua_State*, int)|是否是C函数或者Lua函数| |lua_islightuserdata(lua_State*, int)|是否是用户自定义类型指针| |lua_isnil(lua_State*, int)|是否是空| |lua_isnone(lua_State*, int)|是否是有效的| |lua_isnoneornil(lua_State*, int)|是否是上面两者| |lua_isnumber(lua_State*, int)|是否是数字| |lua_isstring(lua_State*, int)|是否是字符串| |lua_istable(lua_State*, int)|是否是table| |lua_isthread(lua_State*, int)|是否是线程| |lua_isuserdata(lua_State*, int)|是否是用户类型,包括full和light| |lua_type(lua_State*, int)|返回元素的类型,对应LUA_TNIL等枚举| |lua_typename(lua_State*, int)|返回元素的类型名称|@获取栈中的元素并转换成C类型@
table(table table-bordered). |_.函数|_.说明|_.返回值类型| |lua_toboolean(lua_State*, int)|把元素转换成C的布尔类型的值|int| |lua_tocfunction(lua_State*, int)|把元素转换成C的函数|lua_CFunction| |lua_tointeger (lua_State*, int)||lua_Integer| |lua_tolstring (lua_State*, int, size_t *len)||const char*| |lua_tonumber (lua_State*, int)||lua_Number| |lua_topointer (lua_State*, int)||const void*| |lua_tostring (lua_State*, int)||const char*| |lua_tothread (lua_State*, int)||lua_State| |lua_touserdata (lua_State*, int)||void*|@栈内元素的操作@
table(table table-bordered). |_.函数|_.说明|| |lua_gettop(lua_State*)|返回栈的元素个数,同时也是栈顶元素的索引| |lua_settop(lua_State*, int)|设置某个元素为栈顶元素,该元素之上的元素会被清除| |lua_pushvalue(lua_State*, int)|压入(拷贝)一个已经存在栈的元素至栈顶| |lua_insert(lua_State*, int)|移动栈顶元素至某个位置| |lua_remove(lua_State*, int)|删除栈中某个元素| |lua_replace(lua_State*, int)|替换栈顶元素至某个位置,相应那个位置的元素至栈顶|参考:http://book.luaer.cn
参考:http://www.lua.org/manual/5.1/manual.html