这是第三篇了,lua的语言基础学习差不多就结束了,接下来就是该学习,热更新相关的知识了。
lua学习(二)
在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
--- 写成一行
mytable = setmetatable({},{})
这是 metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
我们可以在使用 lua 命令进入交互模式查看:
$ lua
Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio
\> other = { foo = 3 }
\> t = setmetatable({}, { __index = other })
\> t.foo
3
\> t.bar
nil
如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。
__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。
function TestTumble()
Metatable = setmetatable({key1 = "values"},{__index = {key2 = "value"}})
print(Metatable.key1)
print(Metatable.key2)
end
TestTumble()
---values
---value
模式 | 描述 |
---|---|
__add | 对应的运算符 ‘+’. |
__sub | 对应的运算符 ‘-’. |
__mul | 对应的运算符 ‘*’. |
__div | 对应的运算符 ‘/’. |
__mod | 对应的运算符 ‘%’. |
__unm | 对应的运算符 ‘-’. |
__concat | 对应的运算符 ‘…’. |
__eq | 对应的运算符 ‘==’. |
__lt | 对应的运算符 ‘<’. |
__le | 对应的运算符 ‘<=’. |
--- 求出表的长度,因为适用# 因为下标没有按照顺序排列而造成错误
function table_max(t)
local max = 0
for i,v in ipairs(t) do
if max < i then
max = i
end
end
return max
end
myTable = setmetatable({1,4,7},{__add = function(myTable,newTable)
for i =1 ,table_max(newTable) do
table.insert(myTable,table_max(myTable)+1 ,newTable[i])
end
return myTable
end
})
newTable = {2,5,8}
myTable = myTable + newTable
for i, v in ipairs(myTable) do
print(v)
end
---147258
__tostring 元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容:
mytable = setmetatable({ 10, 20, 30 }, {
__tostring = function(mytable)
sum = 0
for k, v in pairs(mytable) do
sum = sum + v
end
return "表所有元素的和为 " .. sum
end
})
print(mytable)
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。协同程序可以理解为一种特殊的线程,可以暂停和恢复其执行,从而允许非抢占式的多任务处理。协同是非常强大的功能,但是用起来也很复杂。
方法 | 描述 |
---|---|
coroutine.create() | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
coroutine.resume() | 重启 coroutine,和 create 配合使用 |
coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 |
coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 coroutine 的线程号 |
function TestCor()
print("TestCor 协程开始执行。。。")
local value = coroutine.yield("暂停了!!!")
print("协程恢复。。。传入的值:".. tostring(value))
print("协程结束!!")
end
--创建一个协程程序
local cor = coroutine.create(TestCor)
-- status :返回的时候重启成功,result 返回的就是内容
local status,result = coroutine.resume(cor)
print(result) --暂停了!!!
--再次重启继续执行剩下的代码
local status1,result1 = coroutine.resume(cor,20)
status = coroutine.status(cor)
print(result1)-- 协程恢复。。。传入的值:20 协程结束!!
print(status1)
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
主要区别归纳如下:
Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。
Lua 实现了一个增量标记-扫描收集器。 它使用这两个数字来控制垃圾收集循环: 垃圾收集器间歇率和垃圾收集器步进倍率。 这两个数字都使用百分数为单位 (例如:值 100 在内部表示 1 )。
垃圾收集器间歇率控制着收集器需要在开启新的循环前要等待多久。 增大这个值会减少收集器的积极性。 当这个值比 100 小的时候,收集器在开启新的循环前不会有等待。 设置这个值为 200 就会让收集器等到总内存使用量达到 之前的两倍时才开始新的循环。
垃圾收集器步进倍率控制着收集器运作速度相对于内存分配速度的倍率。 增大这个值不仅会让收集器更加积极,还会增加每个增量步骤的长度。
不要把这个值设得小于 100 , 那样的话收集器就工作的太慢了以至于永远都干不完一个循环。 默认值是 200 ,这表示收集器以内存分配的"两倍"速工作
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式。
简单模式在做一些简单的文件操作时较为合适。但是在进行一些高级的文件操作的时候,简单模式就显得力不从心。例如同时读取多个文件这样的操作,使用完全模式则较为合适。
file = io.open (filename [, mode])
模式 | 描述 |
---|---|
r | 以只读方式打开文件,该文件必须存在。 |
w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
r+ | 以可读写方式打开文件,该文件必须存在。 |
w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
a+ | 与a类似,但此文件可读可写 |
b | 二进制模式,如果文件是二进制文件,可以加上b |
+ | 号表示对文件既可以读也可以写 |
file = io.open("Text.txt","r")
for line in file:lines() do
print(line)
end
end
TestIo()
安全模式
通常我们需要在同一时间处理多个文件。我们需要使用 file:function_name 来代替 io.function_name 方法。以下实例演示了如何同时处理同一个文件:
首先我们知道面向对象实际上要做的就是做出来类,但是lua里面没有类这一概念,所以这就需要我们自己模拟。
lua 中的 function 可以用来表示方法。那么LUA中的类可以通过 table + function 模拟出来。
-- 面向对象的思维 table 相当于是类
-- 赋值一个新的表下 相当于是一个new
function clone(tab)
local temp = {}
for key, val in pairs(tab) do
temp[key] = val
end
return temp
end
-- 将一个table里面的所有数据全部都附加到另外一个table上
function copy(dist,tab)
for key, val in pairs(tab) do
dist[key] = val
end
end
People ={}
--[[
function People.sayHi()
print("People say Hi !")
end
]]
People.SayHi = function(self)
print("People say Hi !" .. self.name)
end
--相当于构造函数
People.new = function(name)
local self = clone(People)
self.name = name
return self
end
--相当于是继承
Man = {}
Man.new = function(name)
local self = People.new(name)
-- 把所有的都付给people的实例
copy(self,Man)
return self
end
Man.sayHello = function(self)
print("Man SAY HELLO :" .. self.name)
end
-- 相当于声明对象
--local p = clone(People)
--[[local p = People.new("zhang san")
p:SayHi()]]
--方法的重载
Man.SayHi = function(self)
print("Man say HI" .. self.name)
end
local m = Man.new("li si")
-- :将冒号左边的值隐士的当作参数传给右边的值
m:sayHello()
m:SayHi()
使用闭包的方法来模拟类
闭包:函数内部定义的方法是无法在函数外部访问的,但是使用闭包可以创建一个封闭的作用域,使得内部定义的方法可以继续访问函数外部的变量和参数。简单理解就是 :方法套方法
function People(name)
local self = {}
local function init()
self.name = name
end
function self.sayHi()
print("People say hi ".. self.name)
end
init()
return self
end
function Man(name)
local self = People(name)
self.sayHello = function()
print("Hello"..self.name)
end
return self
end
local p = People("li si")
local m = Man("wan wu")
m.sayHi()
m.sayHello()
p.sayHi()