Lua基础学习(四)

上一篇: Lua基础学习(三)https://blog.csdn.net/sun_zeliang/article/details/86677031

 

Lua元表

元表的作用

 在Lua中,每个值通常都有一套预定义的操作集合,例如数字的相加,字符串的连接。而table比较特殊,没有办法直接将两个table相加,没有办法对函数作比较,也没有办法调用一个字符串,这个时候就需要元表来完成。

元表的方法

 元表中有两个重要的方法:

setmetatable(table,metatable) 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。

getmetatable(table) 返回对象的元表(metatable)。

示例:

mytable1={}
mytable2={}
mymetatable={}
setmetatable(mytable2,mymetatable)
print("mytable1的元表为:",getmetatable(mytable1))
print("mytable2的元表为:",getmetatable(mytable2))
print("hi的元表为:",getmetatable("hi"))
print("10的元表为:",getmetatable(10))

输出: 

 

通过观察输出发现, mytable1没有设置元表,mytable2设置了元表,在默认情况下,lua里面的字符串是有元表的,其他类型的值都没有,还有在lua代码中,只能设置table的元表,如果要设置其他类型的值的元表,必须通过C代码。

元表的使用

__add对应的运算符 '+'.
__sub对应的运算符 '-'.
__mul对应的运算符 '*'.
__div对应的运算符 '/'.
__mod对应的运算符 '%'.
__unm对应的运算符 '-'.
__concat对应的运算符 '..'.
__eq对应的运算符 '=='.
__lt对应的运算符 '<'.
__le对应的运算符 '<='.
Set = {}
Set.mt = {}  --共享元表

function Set.new(l)  --根据参数列表中的值创建一个新的集合
  local set = {}
  setmetatable(set,Set.mt)
  for _, v in ipairs(l) do set[v] = true end  --把集合中的每个值都作为set的索引
  return set
end

function Set.union(a,b)   --并集
  local res = Set.new{}
  for i in pairs(a) do res[i] = true end
  for i in pairs(b) do res[i] = true end
  return res
end

function Set.intersection(a,b)   --交集
  local res = Set.new{}
  for i in pairs(a) do res[i] = b[i] end
  return res
end

function Set.tostring(set)
  local s="{"
  local sep=""
  for i in pairs(set) do
    s = s..sep..i
	sep=","
  end
  return s.."}"
end

function Set.print(set)
  print(Set.tostring(set))
end

Set.mt.__add=Set.union
s1 = Set.new{6,2}
s2 = Set.new{2,4}

s3 = s1 + s2
Set.print(s3)

Set.mt.__mul=Set.intersection

s4 = s1*s2
Set.print(s4)

 

__index元方法:

当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。

 感觉有点像C#的访问器get,只是__index可以追踪查找。

示例:

Window = {}   --创建一个名字空间
Window.prototype = {x=0,y=0,width=50,height=100}
Window.mt = {}   --创建元表

function Window.new(o)   --声明一个构造函数
  setmetatable(o,Window.mt)
  return o
end

Window.mt.__index = function(table,key)  --定义__index元方法
  return Window.prototype[key]
end

w = Window.new{x=10,y=20}
print(w.width)
print(w.w)

输出:

 

在Lua中,如果检测到w中没有width字段,但是在元表中有__index字段,那么Lua就会以 w 和 width 来调用__index元方法,然后返回结果。

__index元方法不必一定是一个函数,也可以是一个table,上面__index的声明就可以改写成:

Window.mt.__index = Window.prototype

 这种写法更便捷,且更直观,如果在w 中没有找到,就会到Window.prototype 里继续查找,类似于访问 Window.prototype["windth"]。

将函数作为__index元方法的优势在于灵活,但是相较于table 会有更大的开销。

__newindex元方法:

和前面的__index 元方法类似,区别在于__index 是访问,而__newindex 是修改。

只读的table,示例:

function ReadOnly(t)
  local p = {}
  local mt = {
    __index = t,
	__newindex = function(t,k,v)
	  error("attempy to update a read-only table",2)
	end
  }
  setmetatable(p,mt)
  return p
end

days = ReadOnly{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}

print(days[1])
days[2] = "Noday"
print(days[3])

输出:

Lua协同程序

线程和协同程序区别

线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。

在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。

协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

协同程序操作

coroutine.create()   创建一个协同程序

coroutine.resume()  启动或再次启动一个暂停的协同程序

coroutine.status()  返回的是协同程序的状态

coroutine.yield()  挂起一个协同程序

coroutine.wrap()  和create类似,也是创建协同程序,但是warp返回的不是协同程序本身,返回的是一个函数

示例:

co = coroutine.create(function() print("hi") end)  --创建一个协同程序
print(co)
print(coroutine.status(co))   --打印协同程序co的状态
coroutine.resume(co)     --启动或再次启动一个暂停的协同程序
print(coroutine.status(co))

co = coroutine.create(function()
	  for i=1,5 do
	    print("co",i)
		coroutine.yield()  --将协同程序挂起
	  end
	end)
coroutine.resume(co)  --输出 1 后被挂起
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
print(coroutine.resume(co))  --输出 false	cannot resume dead coroutine

co = coroutine.create(function(a,b) print("co",a+b,a-b) end)
print(coroutine.resume(co,20,10))  --输出 co 30 10   true

co = coroutine.create(function(a,b) coroutine.yield(a+b,a-b) end)
print(coroutine.resume(co,20,10)) --输出 true 30 10

co = coroutine.create(function() print("co",coroutine.yield()) end)
coroutine.resume(co)        --什么都没输出
coroutine.resume(co,5,6)    --输出 co 5 6

co = coroutine.create(function() return 6,7 end)
print(coroutine.resume(co))  --打印 6 7

 使用协同程序

实现迭代器

 实例:

function permgen(a,n)
  n = n or #a
  if n <= 1 then
    coroutine.yield(a)
  else
    for i=1,n do
      a[n],a[i] = a[i],a[n]  --交换位置
      permgen(a,n-1)
      a[n],a[i] = a[i],a[n]  --恢复位置
	end
  end
end

function permutations(a)
  return coroutine.wrap(function() permgen(a) end)
end


function printResult(a)
  for i=1,#a do
    io.write(a[i]," ")
  end
  io.write("\n")
end

for p in permutations{"a","b","c"} do
  printResult(p)
end

输出:

 

上一篇: Lua基础学习(五)https://blog.csdn.net/sun_zeliang/article/details/87459365

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值