Lua基础
2016-12-27 14:58
127 查看
git地址
图片版地址
Lua
1、类型
string number function boolean nil userdata(自定义) thread table
1.1 table
1.1.1 遍历
for i = 1, #a do
print(a[i])
end
2、表达式
2.1 算术操作符
+ - * / % ^
x^0.5 = x的平方根. x^(-1/3) = x立方根的倒数
2.2 关系操作符
2.2.1 < > <= >= == ~=(不等)
2.2.2 对于table、userdata、和函数 ,Lua 是做引用比较的,只有当他们引用同一个对象时,才认为他们是相等的
a = {}; a.x = 1; a.y = 1;
b = {}; b.x = 1; b.y = 1;
c = a;
结果 : a == c; a ~= b;
2.2.3 只能对两个数组或者字符串作大小性比较。Lua是安装字母次序比较字符串的,具体的字母次序取决于对Lua的区域设置
“qwertyuiop” 中 “qwe” > “qwr”
2.3 逻辑操作符
and、or、not 所有的逻辑操作符将false 和 nil 视为假,将其他的任何东西视为真
2.3.1 and print(4 and 5) –>5
print(false and 4) –>false
or print(4 or 5) –>5
print(false or 5) –>5
not 永远只返回true 或 false
print(not nil) –>true
print(not false) –>true
2.4 字符串连接 ..
print(“Hello” .. “World”) –>HelloWorld
print(0 .. 1) –>01
#Lua 中的字符串是不可变的值,连接操作符只会创建一个新的字符串,而不会对其原操作数进行任何改变
a = “Hello”
print(a .. “World”) –>HelloWorld
print(a) –>Hello
2.5 优先级
^ not # -(负号) * / % + - .. < > <= >= ~= == and or
^ .. 为右结合
a + i < b / 2 + 1 ======= (a + i) < ((b / 2) + 1)
x^y^z ====== x^(y^z)
2.6 table 构造式
用于创建和初始化table的表达式。Lua特有的一种表达式。
days = {“1”, “2”, “3”}
a = {x = 10, y = 20}
a = {}; a.x = 10; a.y = 20;
图片版地址
Lua
1、类型
string number function boolean nil userdata(自定义) thread table
1.1 table
1.1.1 遍历
for i = 1, #a do
print(a[i])
end
2、表达式
2.1 算术操作符
+ - * / % ^
x^0.5 = x的平方根. x^(-1/3) = x立方根的倒数
2.2 关系操作符
2.2.1 < > <= >= == ~=(不等)
2.2.2 对于table、userdata、和函数 ,Lua 是做引用比较的,只有当他们引用同一个对象时,才认为他们是相等的
a = {}; a.x = 1; a.y = 1;
b = {}; b.x = 1; b.y = 1;
c = a;
结果 : a == c; a ~= b;
2.2.3 只能对两个数组或者字符串作大小性比较。Lua是安装字母次序比较字符串的,具体的字母次序取决于对Lua的区域设置
“qwertyuiop” 中 “qwe” > “qwr”
2.3 逻辑操作符
and、or、not 所有的逻辑操作符将false 和 nil 视为假,将其他的任何东西视为真
2.3.1 and print(4 and 5) –>5
print(false and 4) –>false
or print(4 or 5) –>5
print(false or 5) –>5
not 永远只返回true 或 false
print(not nil) –>true
print(not false) –>true
2.4 字符串连接 ..
print(“Hello” .. “World”) –>HelloWorld
print(0 .. 1) –>01
#Lua 中的字符串是不可变的值,连接操作符只会创建一个新的字符串,而不会对其原操作数进行任何改变
a = “Hello”
print(a .. “World”) –>HelloWorld
print(a) –>Hello
2.5 优先级
^ not # -(负号) * / % + - .. < > <= >= ~= == and or
^ .. 为右结合
a + i < b / 2 + 1 ======= (a + i) < ((b / 2) + 1)
x^y^z ====== x^(y^z)
2.6 table 构造式
用于创建和初始化table的表达式。Lua特有的一种表达式。
days = {“1”, “2”, “3”}
a = {x = 10, y = 20}
a = {}; a.x = 10; a.y = 20;
p = {color = "blue", thick = 2, npoints = 4, {x = 1, y = 0}, {x = 2, y = 3}, {x = 4, y = 5}, {x = 6, y = 7} } print(p[2].x) print(p[1].y) print(p.color) 2.7 链表 list = nil for line in io.lines() do list = {next = list, value = line} end 3、语句 3.1 赋值 a, b = 1, 2 x, y = y, x 值互换 3.2 局部变量 local i = 1 local x = x //声明一个局部变量并且用一个全局遍历赋值 3.3 程序块 do local x = 1 end 3.4 控制结构 3.4.1 if then else if a < 0 then a = 0 end if a < b then return a else return b end 3.4.2 while local i = 1 while a[i] do print(a[i]) i = i + 1 end 3.4.3 repeat line = io.read() until line ~= "" print(line) 3.4.4 for 数字型for for i=1,10,1 do print(i) end 泛型for days = {"Sun", "Mon", "Tue", "Wed", "Thurs", "Fri", "Sat"} revDays = {} for k, v in pairs(days) do revDays[v] = k end for v in pairs(revDays) do print(v) end 3.4.5 break \ return 由于语法构造的原因,break 和 return 只能是一个快的最后一条语句, 他们应是程序块的最后一条语句,或者是 end、else、until 前的一条语句 3.4.5.1 break local x = 1 while x do if x == 10 then break end x = x + 1 print(x) end 3.4.5.2 return function foo() return -------->使用错误 do return end -------->使用正确 x = 1 y = x end 4、函数 函数需要将所有参数放到一对圆括号中,即使调用函数时没有参数,也必须写出一对括号。 特例:一个函数若只有一个参数,并且此函数是一个字面字符串或 table 构造式那么圆括号可有可无 print "hello" === print("hello") dofile 'a.lua' === dofile('a.lua') print [[a multi-linemessage]] === print([[a multi-linemessage]]) f{x = 10, y = 20} === f({x = 10, y = 20}) type{} === type({}) 4.1 多重返回值 function customMax(t) local mi = 1 local max = t[mi] for i, val in pairs(t) do if val > max then max = val mi = i end end return mi, max end x, y = customMax {10,4,1,5,12,53,123,54,2,33,44,64} print(x, y) 4.2 变长参数 function customAnd( ... ) local x = 1 for i, val in pairs(...) do x = x + val end print(x) end customAnd({10,2,3,1}) 4.3 具名实参 rename(old = "temp.lua", new = "temp1.lua") ------>无效 rename( {old = "temp.lua", new = "temp1.lua"} ) ------->有效,括号可以省略 5、深入函数 function foo(x) return 2 * x end foo = function(x) return 2 * x end 5.1 高阶函数 接受另一个函数作为实参的称其为"高阶函数" names = {"Peter", "Paul", "Mary"} grades = {Mary = 10, Paul = 7, Peter = 8} table.sort(names, function ( n1, n2 ) return grades[n1] > grades[n2] end) 5.2 closure (闭合函数) function newCounter( ) local i = 0 return function ( ) i = i + 1 return i end end c1 = newCounter() print(c1()) -------------->1 print(c2()) -------------->2 5.3 尾调用(proper tail call) function f(x) return g(x) end 当f调用完之后就再无其他事情可做了。 因此在这种情况中程序就不需要返回那个"尾调用"所在的函数了.所以在"尾调用"之后, 程序也不需要保存热河关于该函数的栈信息了。 当g返回时,执行控制权可以直接返回到调用f的那个点上。使得在进行"尾调用"时不耗费任何栈控件。 称为"尾调用消除" return x[i].foo(x[j] + a * b, i + j) ---是 return g(x) + 1 ---不是 6、迭代器与泛型for 6.1 迭代器 function allwords( ) local line = io.read() --当前行 local pos = 1 --一行中的当前位置 return function ( ) ---迭代器函数 while line do ---若为有效的行内容就进入循环 local s, e = string.find(line, "%w+", pos) if s then ---是否找到一个单词 pos = e + 1 ---该单词的下一个位置 return string.sub(line, s, e) ---返回该单词 else line = io.read() ---没有找到单词,尝试下一行 pos = 1 ---在第一个位置上重新开始 end end return nil ---没有其余行了,遍历结束 end end 6.2 泛型for for <var-list> in <exp-list> do <body> end <var-list> 是一个或多个变量名的列表,以逗号分隔 <exp-list> 是一个或多个表达式的列表,以逗号分隔 for k, v in pairs(t) do print(k, v) end 7 编译 loadstring i = 0 f = loadstring("i = i + 1; print(i)") 7.1 loadstring 在编译时不涉及词法域,所以操作的是全局变量,因为loadstring总是在全局环境中编译它的字符串 i = 32 local i = 0 f = loadstring("i = i + 1; print(i)") g = function ( ) i = i + 1 print(i) end f() ------>33 g() --------1 7.2 如果代码中有语法错误,loadstring会返回nil,最终的错误消息可能会是"attempt to call a nil value" 为了更清楚的显示错误消息,使用assert assert(loadstring(s))() 7.3 速度 f = loadstring("i = i + 1") f = function ( ) i = i + 1 end 第二块代码快的多,因为他只在编译对应用程序块时编译一次 第一块代码在每次调用loadstring 时都被重新编译 8、error检测 8.1 数字检测 tonumber(i) 如果为数字则返回数字否则返回nil 8.2 assert() 函数检查其第一个参数是否为true,若为true,则简单的返回该函数,否则引发一个错误,输出第二个参数 8.3 pcall ------protected call 保护模式调用 9、协程 9.1 四种状态 suspended 挂起、running 运行、dead 死亡、normal 正常 当创建一个协同程序时,它处于挂起状态。 9.2 yield co = coroutine.create(function ( ) for i=1,10 do print(i) coroutine.yield() end end) 该函数可以让一个运行中的协同程序挂起,而之后可以再恢复他的运行. 9.3 resume 是在保护模式中运行的。因此,如果在一个协同程序的执行中发生任何错误,lua是不会显示错误信息的。 而是将执行权返回给resume调用。 当一个协同程序A唤醒另一个协同程序B时,协同程序A就处于一个特殊状态,既不是挂起状态,也不是运行状态,称为"正常"状态 返回值为是否有错误 和 yield的返回值 co = coroutine.create(function ( ) yield return 0, 1, 3 end) print(coroutine.resume(co)) ------>true 0 1 3 9.4 生产者-消费者 function producer( ) while true do local x = io.read() send(x) end end function consumer( ) while true do local x = reveive() io.write(x, "\n") end end function receive( ) local status, value = coroutine.resume(producer) return value end function send( x ) coroutine.yield(x) end 9.5 过滤器(filter) function reveive( prod ) local status, value = coroutine.resume(prod) return value end function send( x ) coroutine.yield(x) end function producer( ) return coroutine.create(function ( ) while true do local x = io.read() send(x) end end) end function filter( prod ) return coroutine.create(function ( ) for line = 1, math.huge do local x = receive(prod) x = string.format("%5d %s", line, x) send(x) end end) end function consumer( prod ) while true do local x = reveive(prod) io.write(x, "\n") end end 10、数据结构 10.1 字符串缓冲 逐行地读取一个文件 local buff = "" for line in io.lines() do buff = buff .. line .. "\n" end 11、元表 metatable 元方法 meatmethod Lua 中只能设置table的元表 可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。 action = {} --元表 function action.new( value ) local temp = {} setmetatable(temp, action) --元表赋值 for k, v in pairs(value) do temp[#temp + 1] = v end return temp end -- table转string function action.tostroing( value ) return table.concat( value, ", ", 1, #value ) end function action.add( source, addition) -- local temp = {} -- setmetatable(temp, action) -- local source = value.source -- local addition = value.addition for k, v in pairs(addition) do source[#source + 1] = v end return action.tostroing(source) end a = action.new{1,2,3} b = {4,5,6} -- print(action.add{source = a, addition = b}) print(action.add(a, b)) 11.1 在元表中,每种算术操作符都有对应的字段名。 __add __mul __sub __div __unm(相反数) __mod(取模) __pow(乘幂) __concat(描述连接操作符的行为) 11.2 重载操作符 __index原方法 __newindex action = {} function action.tostroing( value ) return table.concat( value, ", ", 1, #value ) end function action.__add( a, b ) for v in pairs(a) do a[v] = a[v] + b end return action.tostroing(a) end function action.__index(table, key) print("当访问table中不存在的key值时会调用 __index 方法,比如现在 : " .. key) return "error" end function action.__newindex(table, key, value) local temp = table print("现在将要添加新的key值和与其对应的value :") print("key : " .. key) print("value : " .. value) -- temp[key] = value -- return action.tostroing(table) end a = {1,2,3} setmetatable(a, action) print("重载 + :") print( a + 3) print("\n") b = {1,2,3} setmetatable(b, action) print("访问table中不存在的key值 : ") print(b[4]) print("\n") c = {1,2,3} setmetatable(c, action) print("添加新的key值和与其对应的value : ") c[4] = 4 print(action.tostroing(c)) print("\n") 11.3 __index 还可以是一个table 当它是一个函数时候,lua以table和不存在的key作为参数来调用该函数,当它是一个table时候, lua就以相同的方式来重新访问这个table a = {1,2,3} b = {4,5,6,7} c = {} setmetatable(a, c) c.__index = b print(a[4]) -------->7 12、环境 Lua 将所有的全局变量保存在一个常规的table _G 中 for n in pairs(_G) do print(n) end 12.1 具有动态名字的全局变量 有些变量的名称存储在另一个变量中,或者需要计算才能得到,为了获取这个变量的值 value = loadstring("return" .. varname)() 如果varname 是 x ,那么连接操作就是字符串return x。 这样做包含了一个新程序块的创建和编译。 value = _G[varname] 效率高 12.2 全局变量声明 大型程序中简单的检测与创建全局变量 setmetatable(_G, { __index = function ( _, n ) print("没有此全局变量" .. n) end, __newindex = function ( table, k, value ) print("add a global variable") rawset(table, k, value) end }) a = 1; print(a) print(b) 12.3 通过setfenv来改变一个函数的环境 a = 1 setfenv(1, {g = _G}) g.print(a) ----->nil g.print(g.a) ---->1 13、模块与包 13.1 require 使用模块 testLib.lua文件: testLib = {} function testLib.new( value ) local temp = {} for k, v in pairs(value) do temp[#temp + 1] = v end return temp end return testLib test.lua文件 lib = require "testLib" a = lib.new{1,2,3} function tostroing( value ) return table.concat( value, ", ", 1, #value ) end print(tostroing(a)) --->1,2,3 13.2 module testLib.lua 文件 lib = require "testLib" a = lib.new{1,2,3} function tostroing( value ) return table.concat( value, ", ", 1, #value ) end print(tostroing(a)) test.lua 文件 lib = require "testLib" a = lib.new{1,2,3} function tostroing( value ) return table.concat( value, ", ", 1, #value ) end print(tostroing(a)) 13.3 require 目录 lua 没有目录的概念 require "a.b" ./a/b.lua /usr/local/lua/a/b.lua /usr/local/lua/a/b/init.lua 14 面向对象 14.1 self 使用self参数是所有面向对象语言的一个核心, 大多数面向对象语言都能对程勋元隐藏部分self参数, 从而使程序员不必显示地声明这个参数, Lua只需使用冒号就能隐藏该参数 function Account:withdraw( v ) self.balance = self.balance - v end 调用时: a = {balance = 0, withdraw = Account.withdraw} a:withdraw(100) 14.2 继承 示例1: a = {1,2,3} b = {4,5,6,7} c = {} setmetatable(a, c) c.__index = b print(a[4])----->7 示例2: a = {base = 1} setmetatable(a, a) function a:add( value ) self.base = self.base + value return self.base end b = {} setmetatable(b, b) b.__index = a c = {} setmetatable(c, c) c.__index = a print(a:add(1)) --->2 print(b:add(1)) --->3 print(c:add(1)) --->3 14.3 多重继承 local function search( k, plist ) for i=1, #plist do local v = plist[i][k] if v then return v end end end function createClass( parents ) local c = {} local parents = parents setmetatable(c, {__index = function ( t, k ) return search(k, parents) end}) c.__index = c function c:new( o ) o = o or {} setmetatable(o, c) return o end return c end a = {aBase = 1} setmetatable(a, a) function a:add( value ) self.aBase = self.aBase + value end b = {bBase = 9} setmetatable(b, b) function b:sub( value ) self.bBase = self.bBase - value end c = createClass{a, b} c:add(1) c:sub(1) print("c aBase : " .. c.aBase) print("c bBase : " .. c.bBase) 14.4 私密性 私有性 function new( init ) local self = {value = init} local add = function ( addition ) self.value = self.value + addition end local sub = function ( sub ) self.value = self.value - sub end local get = function ( ) return self.value end return {add = add, sub = sub, get = get} end count = new(1) count.add(1) print(count.get()) 14.5 单一方法 的做法 function new( init ) local self = {value = init} return function ( action, value ) if action == "add" then self.value = self.value + value elseif action == "sub" then self.value = self.value - value elseif action == "get" then return self.value end end end count = new(1) print("initial value is : " .. count("get")) count("add", 1) print("after add 1 : " .. count("get")) count("sub", 1) print("after sub 1 : " .. count("get")) 15 弱引用 lua自动回收,只回收弱引用的的类型、为nil的全局变量。 全局变量使用完后需要手动置为nil table中有key和value,这两者都可以包含任意类型的对象, 通常收集器不会回收一个可访问table中作为key或value的对象。 也就是说这些key和value都是强引用,他们会阻止对其所引用对象的回收。 在一个弱引用table中。key和value都是可以回收的。 只要key或者value一方为若引用,那么他们所在的整条目都会从table中删除 15.1 table 弱引用 table的弱引用类型是通过其元表中的__mode字段来决定的。 这个字段的值应为一个字符串, 如果这个字符串包含'k',那么这个table的key是弱引用 如果包含'v',那么这个table的value是弱引用 a = {} b = {__mode = "k"} setmetatable(a, b) key = {} a[key] = 1 key = {} a[key] = 2 collectgarbage() for k, v in pairs(a) do print(v) end -------->2 15.2 备忘录函数 空间换时间 local results = {} function mem_loadstring( s ) local res = results[s] if nil == res then res = assert(loadstring(s)) results[s] = res end return res end 转为弱引用: local results = {} setmetatable(results, {__mode = "v"}) function mem_loadstring( s ) local res = results[s] if nil == res then res = assert(loadstring(s)) results[s] = res end return res end 16 数学库 三角 math.sin cos tan asin acos ... 指数对数 exp log log10 取整函数 floor ceil max min 生成伪随机数 random randomseed math.random() ---[0,1) math.random(6) ---[1,6] math.random(m,n) ---[m,n] math.randomseed(os.time()) ---os.time 表示从某个时间点开始至今的秒数 pi huge 为Lua可以表示的最大数字 17 table库 17.1 插入和删除 action = {} function action.tostring( value ) return table.concat( value, ", ", 1, #value ) end a = {1,2,3} table.insert(a, 1, 4) print(action.tostring(a)) --4,1,2,3 b = {1,2,3} table.insert(b, 4) print(action.tostring(b)) --1,2,3,4 c = {1,2,3} table.remove(c) print(action.tostring(c)) --1,2 d = {1,2,3} table.remove(d, 1) print(action.tostring(d)) --2,3 17.2 排序 action = {} function action.tostring( value ) return table.concat( value, ", ", 1, #value ) end a = {3,6,1,4,5,2} table.sort( a, function ( a, b ) return a < b end ) print(action.tostring(a)) --1, 2, 3, 4, 5, 6 table.sort(a, function ( a, b ) return a > b end) print(action.tostring(a)) --6, 5, 4, 3, 2, 1 18 字符串库 18.1 基础字符串函数 string.len(s) 返回字符串s的长度 string.rep(s, n) s:rep(n) 返回字符串s重复n次的结果 string.lower(s) 返回一份s的副本,其中所有的大写字母转换成小写 string.upper(s) 小写转大写 string.sub(s, i, j) 字符串s中提取第i个到第j个字符 字符串第一个字符的索引是1,索引-1代表字符串的最后一个字符 索引-2代表倒数第二个字符 string.sub(j, -1) == string.sub(j) 第二个参数默认为-1 string.char string.byte 用于转换字符及内部数值表示 string.char(97) --a string.byte("abc") --97 string.byte("abc", 2) --98 string.byte("abc", 1, 2) --97 98 18.1.1 format print(string.format("pi = %.4f", math.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> 18.2 模式匹配函数 fin match gsub(全局替换) gmatch(全局匹配) 18.2.1 string.find 返回起始索引和结尾索引,如果没有找到返回nil s = "hello world" i, j = string.find(s, "hello") print(i, j) --- 1 5 string.find 函数还具有一个可选的第三个参数,他是一个索引告诉函数应该从目标字符串的那个位置开始搜索 18.2.2 string.match 函数 string.match("hello world", "hello") -- hello data = "Today is 17/7/1990" string.match(date, "%d+/%d+/%d+") ---17/7/1990 18.2.3 string.gsub s, k = string.gsub("all lii", "l", "x") --- axx xii --3 可选第四个参数,限制替换次数 k = 3 替换次数 18.2.3.1 第三个参数还可以是一个table(包括_G) 用来替换 group = {} group.a = "Lua" group.b = "great" print(string.gsub("$a is $b", "$(%w+)", group)) -- Lua is great 2 还可以是一个方法 s ="a%2Bb%3Dc" s = string.gsub(s, "%%(%x%x)", function ( h ) return string.char(tonumber(h, 16)) end) print(s) -- a+b=c 18.2.4 string.gmatch d = "123qwertyuiopasdfghjklqwer" a = string.gmatch(d, "qwe") for w in a do print(w) --qwe end 18.3 模式 18.3.1 %a 字母 %c 控制字母 %d 数字 %l 小写字母 %p 标点符号 %s 空白字母 %u 大写字母 %w 字母和数字字符 %x 十六进制数字 %z 内部表示为0的字符 18.3.2 需要转义的字符 ().%+-*?[]^$ 18.3.3 .- .*的区别 test = "int x; /*x*/ int y; /*y*/" print(string.gsub(test, "/%*.*%*/", "<COMMENT>")) -- int x; <COMMENT> 1 print(string.gsub(test, "/%*.-%*/", "<COMMENT>")) -- int x; <COMMENT> int y; <COMMENT> 2 18.3.4 ? a = "qwer+1234asdf-5432" print(string.gsub(a, "[+-]?%d+", "A")) -- qwerAasdfA 2 18.3.5 如果模式以'^'起始,那么他只会匹配目标字符串的开头部分 以'$'结尾,只匹配结尾部分 a = "123qwer+1234asdf-5432" print(string.match(a, "^%d+")) -- 123 print(string.match(a, "%d+$")) -- 5432 18.3.6 "%b<x><y>" 以x开头y结尾的字符串 a = "hello (13qwer+134asdf-5432)world" print(string.gsub(a, "%b()", "")) -- hello world 1 18.3.7 捕获 模式中表示两个字母序列的部分放在一对括号中,就能捕获到 d = "Today is 17/7/1990" d, m, y = string.match(d, "(%d+)/(%d+)/(%d+)") print(d, m, y) -- 17 7 1990 18.3.8 URL 编码 s ="a%2Bb%3Dc" -- a%2Bb%3Dc s = string.gsub(s, "%%(%x%x)", function ( h ) return string.char(tonumber(h, 16)) end) print(s) --a+b a = "%2B" print(string.gsub(a, "%%(%x%x)", "A")) -- A 1 a = "%2B" print(string.gsub(a, "%%(%x)", "A")) -- AB 1 18.3.9 空白捕捉 () print(string.match("hello", "h()")) -- 2 print(string.match("hello", "l()")) -- 4 19 I/O模型 19.1 简单I/O模型 io.input(filename)调用会以只读模式打开指定的文件,并将其设为当前输出文件。 之后除非再次调用 io.input ,否则所有的输入都将来源于这个文件。 io.write(a..b..c)应该尽量避免,io.write(a,b,c)效果相同并且可以避免连接操作。 19.1.1 write与print不同 write在输出时不会添加像制表符或回车这样的额外字符 print("hello","Lua"); print("Hi") --hello Lua --Hi io.write("hello", "Lua"); io.write("Hi","\n") --helloLuaHi write使用当前输出文件而print总是使用标准输出 print会自动调用其参数的tostring方法因此他还能显示table、函数和nil 19.1.2 io.read从当前输入文件中读取字符串,他的参数决定了要读取的数据 "*all" 读取整个文件 "*line"读取下一行 "*number" 读取一个数字 <num> 读取一个不超过<num>个字符的字符串 19.1.3 io.lines()迭代器 如果只为了迭代文件中的所有行,那么io.lines迭代器更为合适。 local lines = {} for line in io.lines() do lines[#lines + 1] = line end table.sort( lines ) for _,l in ipairs(lines) do io.write(l, "\n") end 19.2 完整 I/O 模型 19.2.1 open io.open(要打开的文件名, 模式字符串) r 读取 w 写入 同时会删除文件原来的内容 a 追加 b 打开二进制文件 print(io.open("non-existent-file", "r")) -- nil non-existent-file: No such file or directory 2 错误代码的解释依赖于系统 典型做法 local f = assert(io.open(filename, mode)) 如果打开失败,错误消息会成为assert的第二个参数,然后显示这个信息 19.2.2 操作 local f = assert(io.open(filename, "r")) local t = f:read("*all") f:close() 19.2.3 性能 1 一次性读取整个文件比逐行地读取要快一些 2 如果文件太大无法一次性读取,尽可能大的块读取,例如8KB大小的块 为了避免在行中间断开,只需在读取一个块时再加上一行 local lines, rest = f:read(BUFFSIZE, "*line") rest 包含了被块所断开的那一行的剩余部分,这样就可以将块与行的剩余部分连接起来, 从而得到一个总是起止于行边界上的块 local BUFSIZE = 3 local f = io.input(arg[1]) local cc, lc, wc = 0,0,0 --字符、行、单词计数器 while true do local lines, rest = f:read(BUFSIZE, "*line") if not lines then break end if rest then lines = lines .. rest .. "\n" end cc = cc + #lines local _, t = string.gsub(lines, "%S+", " ") wc = wc + t _, t = string.gsub(lines, "\n", "\n") lc = lc + t end print(lc, wc, cc) 19.2.4 二进制 local inp = assert(io.open(arg[1], "rb")) local out = assert(io.ioen(arg[2], "wb")) local data = inp:read("*all") data = string.gsub(data, "\r\n", "\n") out:write(data) assert(out:close()) 调用: lua prog.lua file.dos file.unix 19.2.5 文件操作 file:seek() 获取当前位置 file:seek("end") 获取文件大小 file:seek("set", current) 恢复位置 20 操作系统库 20.1 日期和时间 time 、 date print(os.time{year = 2016, month = 1, day = 1, hour = 0, min = 0, sec = 0, isdst = true}) --isdst true 表示夏令时 print(os.time()) --1451577600 print(os.date("today is %a", os.time())) 星期简写 today is Mon print(os.date("today is %A", os.time())) 星期全写 today is Monday print(os.date("today is %b", os.time())) 月份简写 today is Dec print(os.date("today is %B", os.time())) 月份全称 today is December print(os.date("today is %c", os.time())) 日期和时间 today is Mon Dec 5 13:53:31 2016 print(os.date("today is %d", os.time())) 一个月中第几天 today is 05 print(os.date("today is %H", os.time())) 24小时进制小时数 today is 13 print(os.date("today is %I", os.time())) 12小时进制小时数 today is 01 print(os.date("today is %j", os.time())) 一年中第几天 today is 340 print(os.date("today is %M", os.time())) 分钟数 today is 53 print(os.date("today is %m", os.time())) 月份数 today is 12 print(os.date("today is %p", os.time())) 上午下午 today is PM print(os.date("today is %S", os.time())) 秒数 today is 31 print(os.date("today is %w", os.time())) 一星期中第几天 today is 1 print(os.date("today is %x", os.time())) 日期 today is 12/05/16 print(os.date("today is %X", os.time())) 日期 today is 13:53:31 print(os.date("today is %y", os.time())) 两位数年份 today is 16 print(os.date("today is %Y", os.time())) 完整年份 today is 2016 print(os.date("today is %%", os.time())) 如果不带任何参数调用date函数,他会使用%c。 %x %X %c会根据不同的区域和系统而发生变化 函数 os.clock 会返回当前cpu时间的秒数,一般可用于计算一段代码的执行时间 local x = os.clock() local s = 0 for i=1,10000 do s = s + 1 end print(string.format("elapsed time : %2f\n", os.clock() - x)) --elapsed time : 0.000070 20.2 其他系统调用 os.exit() 中止当前程序的执行 os.getenv() 获取一个环境变量的值 os.getenv("Home") 如果一个环境变量没有定义返回nil os.execute()运行一条系统命令 os.execute("mkdir" .. dirname) 21 C API c调用lua #include <stdio.h> #include <string.h> #include "lua.hpp" #include "lauxlib.h" #include "lualib.h" int main (void){ printf("go\n"); lua_State* L = luaL_newstate(); luaL_openlibs(L); lua_close(L); return 0; } 21.1 栈操作 抽象栈在Lua与C之间交换数据 栈中的每个元素都能保存任何类型的Lua值 要获取Lua中的一个值时只要调用一个Lua API函数,Lua就会将制定的值压入栈中 要将一个值传给Lua时,需要先将这个值压入栈,然后调用Lua API,Lua就会获取该值并将其从栈中弹出 Lua以 先出后进 规范操作栈,当调用Lua时,Lua只会改变栈的顶部 C有更大的自由度,他可以检索栈中间的元素,插入删除任意位置 21.1.1 压入元素 void lua_pushnil(lua_State* L); void lua_pushboolean(lua_State* L, int bool); void lua_pushnumber(lua_State* L, lua_Number n); --lua_Number是Lua中的数字类型默认为双精度浮点数 或者单精度浮点数或长整数 void lua_pushinteger(lua_State* L, lua_Integer n); --lua_Integer整数类型足以存储大型字符串的长度 void lua_pushlstring(lua_State* L, const char* s, size_t* len); --Lua中的字符串不是以零结尾需要长度 void lua_pushstring(lua_State* L, const char* s); 还有压入C函数、userdata值的函数 int lua_checkstack(lua_State* L, int sz) --检查栈中是否有足够空间 21.1.2 查询元素 使用索引 第一个压入元素索引为1 第二个2 最后压入元素为-1 倒数第二个-2 21.1.2.1 检查是否为特定类型 int lua_is*(lua_State* L, int index); 实际上,lua_isnumber不会检测值是否为数字类型,而是检测值是否可以转为数字类型 lua_isstring 同样,因此对于任意数字,lua_isstring都返回真 21.1.2.2 返回栈中原色的类型 lua_type 返回一个常量,这些常量定义在头文件lua.h中。 LUA_TNIT LUA_TBOOLEAN LUA_TNUMBER LUA_TSTRING LUA_TTABLE LUA_TTHREAD LUA_TUSERDATA LUA_TFUNCTION 21.1.2.3 取值 lua_to* int lua_toboolean(lua_State* L, int index); lua_Number lua_tonumber(lua_State* L, int index); lua_Integer lua_tointerger(lua_State* L, int index); const char* lua_tolstring(lua_State* L, int index, size_t* len); size_t lua_objlen(lua_State* L, int index); 如果指定元素不具有正确的类型,调用这些函数也不会有问题 ,会返回0或者NULL lua_tolstring 函数会返回一个指向内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。 Luaua只要保证这个对应的字符串值还在栈中,那么这个指针就是有效的。 当Lua调用的一个C函数返回时,LUA就会清空他的栈。 所以不要在C函数之外使用在C函数内获得的指向Lua字符串的指针 21.1.2.4 其他栈操作 int lua_gettop(lua_State* L); --栈中元素的个数,栈顶元素的索引 void lua_settop(lua_State* L, int index); --将栈顶设置为一个指定的位置,修改栈中元素的数量,高出来的丢弃不足的补nil -- lua_settop(L, 0)能清空栈,也可以用负数来索引 一个宏来弹出n个元素 #define lua_pop(L, n) lua_settop(L, -(n) - 1) void lua_pushvalue(lua_State* L, int index); -- 将指定索引上值的副本压入栈 void lua_remove(lua_State* L, int index); --删除指定索引上的元素,该位置只上的所有元素下移填补空缺 void lua_insert(lua_State* L, int index); --上移该位置之上的所有元素来开辟一个空间,将栈顶元素移到该位置 lua_insert(L, -1) -- 将栈顶元素移动到栈顶 void lua_replace(lua_State* L, int index); --弹出栈顶的值并将该值设置到指定索引上,但不会移动任何东西 #include <stdio.h> #include <string.h> #include "lua.hpp" #include "lauxlib.h" #include "lualib.h" void printStack(lua_State* L){ int size = lua_gettop(L); for(int i = 1; i <= size; i++){ int t = lua_type(L, i); switch(t){ case LUA_TSTRING:{ printf("%s", lua_tostring(L, i)); } break; case LUA_TNUMBER:{ printf("%g", lua_tonumber(L, i)); } break; } printf("\n"); } } int main (void){ printf("im in cpp\n"); lua_State* L = luaL_newstate(); lua_pushnumber(L, 1); lua_pushstring(L, "hello lua"); lua_pushnumber(L, 2); printf("source stack is :"); printStack(L); // lua_pushvalue(L, 2); // printf("after pushvalue 2, now stack is :\n"); // printStack(L); lua_close(L); } 编译 gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua 22 扩展应用 22.1 Lua做配置文件 test.lua 文件内容 width = 10 height = 20 cdolua.cpp 文件内容 使用c调用lua读取lua写的配置文件 #include <stdio.h> #include <string.h> #include "lua.hpp" #include "lauxlib.h" #include "lualib.h" void load(lua_State* L, const char* fname, int* w, int* h){ if(luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0)){} lua_getglobal(L, "width"); lua_getglobal(L, "height"); if(!lua_isnumber(L, -2)){} if(!lua_isnumber(L, -1)){} *w = lua_tointeger(L, -2); *h = lua_tointeger(L, -1); printf("width is : %d\n", *w); printf("height is : %d\n", *h); } int main (void){ printf("im in cpp\n"); lua_State* L = luaL_newstate(); int x = 0; int y = 0; load(L, "test.lua", &x, &y); lua_close(L); } 调试加调用 wangpengdeiMac:Unity基础 wp$ gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua wangpengdeiMac:Unity基础 wp$ ./a.out im in cpp width is : 10 height is : 20 22.2 调用方法 test.lua文件 function printTest( ... ) print(...) return 1 end cdolua.cpp文件 #include <stdio.h> #include <string.h> #include "lua.hpp" #include "lauxlib.h" #include "lualib.h" int main (void){ printf("im in cpp\n"); lua_State* L = luaL_newstate(); luaL_openlibs(L); if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0)){ printf("%s\n", "error loadfile"); } lua_getglobal(L, "printTest"); lua_pushstring(L, "1234"); if(lua_pcall(L, 1, 1, 0) != 0){ printf("%s\n", "error lua pcall"); } int z = lua_tonumber(L, -1); printf("z : %d\n", z); lua_close(L); } 编译 wangpengdeiMac:Unity基础 wp$ gcc /Users/wp/Desktop/Unity基础/cdolua.cpp -llua wangpengdeiMac:Unity基础 wp$ ./a.out im in cpp 1234 z : 1 23 Luaua 调用 C ----尼玛我这怎么都不能c文件编译成.a或者.so 23.1 C 函数 示例: static int l_sin(lua_State* L){ double d = lua_tonumber(L, 1); //获取参数 lua_pushnumber(L, sin(d)); //压入结果 return 1; //返回结果的数量 } 所有注册到LUA中的函数都具有相同的原型。定义在lua.h 中的lua_CFunction typedef int (*lua_CFunction) (lua_State* L); 在lua使用这个函数之前,必须注册这个函数。可以使用 lua_pushcfunction 来进行注册。 24 userdata userdata 提供了一块原始的内存区域,可以用来存储任何东西. lua_newuserdata 会根据指定的大小分配一块内存,并将对应的userdata压入栈中,最后返回这个内存块的地址 void* lua_newuserdata(lua_State* L, size_t size); Demo: static struct StudentTag{ char* strName; char* strNum; int iSex; int iAge; } static int Student(lua_State* L){ size_t iBytes = sizeof(struct StudentTag); struct StudentTag* pStudent; pStudent = (struct StudentTag*) lua_newuserdata(L, iBytes); return 1; } //新的userdata已经在栈上可以直接返回给lua static int GetName(lua_State* L){ struct StudentTag* pStudent = (struct StudentTag*)lua_touserdata(L, 1); luaL_argcheck(L, pStudent != NULL, 1, "Wrong"); lua_pushstring(L, pStudent->strName); return 1; } static int SetName(lua_State* L){ struct StudentTag* pStudent = (struct StudentTag*)lua_touserdata(L, 1); luaL_argcheck(L, pStudent != NULL, && pName != "", "Wrong"); pStudent->strName = pName; return 0; } lua: require "luaDoC" local objStudent = Student.new() Student.setName(objStudent, "WP") Student.setAge(objStudent, 15) local strName = Student.getName(objStudent) local iAge = Student.getAge(objStudent) print(strName) print(iAge) 25 元表 userdata 可以代表任何类型。所以当用userdata做参数时候并不能保证类型。 一种辨别不同类型的userdata的方法是,为每种类型创建一个唯一的元表。 每当创建了一个userdata后,就用相应的元表来标记他。 每当得到一个userdata就检查他是否拥有正确的元表。 由于Lua代码不能改变userdata的元表。因此无法欺骗代码。 int luaL_newmetatable(lua_State* L, const char* tName); void luaL_getmetatable(lua_State* L, const char* tName); void* luaL_checkudata(lua_State* L, int index, const char* tName); newmetatable函数会创建一个新的table用作元表,并将其压入栈顶,然后将这个table与注册表中的指定名称关联起来。 getmetatable函数可以在注册表中检索与tname相关联的元表, luaL_checkudata 可以检查栈中指定位置上是否为一个userdata,并且是否具有与给定名称相匹配的元表。 如果该对象不是一个userdata,或者他不具有正确的元表,将会引发一个错误。 否则他会返回这个userdata的地址。 int luaopen_userdatademo(lua_State* L){ luaL_newmetatable(L, "student"); luaL_register(L, "student", arrayFunc); return 1; } static int Student(lua_State* L){ size_t iBytes = sizeof(struct StudentTag); struct StudentTag* pStudent; pStudent = (struct StudentTag*)lua_newuserdata(L, iBytes); luaL_getmetatable(L, "Student"); lua_setmetatable(L, -2); return 1; } static int GetName(lua_State* L){ struct StudentTag* pStudent = (struct StudentTag*)luaL_checkudata(L, 1, "student"); lua_pushstring(L, pStudent->strName); return 1; } 26 数组访问 26.1 Lua中 local metaarray = getmetatable(array.new(1)) metaarray.__index = array.get metaarray.__newindex = array.set metaarray.__len = array.size a = array.new(100) a[10] = true --setarray print(a[10]) --getarray print(#a) --getsize 26.2 C代码注册中修改 static const struct luaL_Reg arrayLib_m[]={ {"__newindex", setarray}, {"__index", getarray}, {"__len", getsize}, {"__tostring", array2string}, {NULL, NULL} };
相关文章推荐
- Lua基础语法-1
- Lua基础之协同程序(coroutine)
- lua基础学习 - 函数多重返回值,变长参数,具名实参
- Lua基础 编译、运行、错误处理
- Lua基础(图)
- lua基础
- Lua 基础:调用函数时用点号还是用冒号
- Cocos2d-x-Lua (2.x)脚本开发之 Lua语言基础
- Lua基础 函数(一)
- Lua学习笔记(1)-基础知识、表达式语法
- Lua基础之math(数学函数库)
- LUA: lua基础.
- cocos2d-x-lua基础系列教程一(hello lua)
- Lua(2) ——基础语法
- Lua语言基础(1) -- 类型与值
- 【笨木头Lua专栏】基础补充04:for循环与迭代器的秘密
- LUA语言基础
- Lua基础(一)——赋值语句、表达式、流程控制、函数
- Lua与C交互之基础操作(1)
- Lua 基础