Lua语言入门(三)

作者: 小飞不会飞_ | 来源:发表于2016-09-24 19:45 被阅读98次

    协同程序

    36、协同程序(coroutine)
    4种状态:挂起(suspended)、运行(running)、死亡(dead)、正常(normal)

    创建(挂起状态):

    local co = coroutine.create(
     function()
      print("coroutine")
     end)
    

    启动或再次启动协程(状态由挂起改为运行):

    coroutine.resume(co)
    

    coroutine在创建的时候不会自动执行。

    检查协程的状态:

    coroutine.status(co)
    

    协程在运行完之后,就处于死亡状态,再也无法返回。

    使用yield:

    local co =  coroutine.create(
     function()
      for i=1,10 do
       print(i)
       coroutine.yield() --运行到这里让该协程挂起,之后通过调用coroutine.resume恢复它的运行
      end
     end
     )
    
    coroutine.resume(co) --1
    coroutine.resume(co) --2
    coroutine.resume(co) --3
    coroutine.resume(co) --4
    coroutine.resume(co) --5
    

    当一个协程 A 唤醒另一个协程 B ,协程 A 就处于一个特殊状态,称为“正常状态”。

    local co =  coroutine.create(
     function(a, b)
      print("the first resume params: ", a, b);  --在第一次调用resume,传递的额外参数都将视为协同程序主函数的参数;
      print("resume params", coroutine.yield("yield return params")) --而yield返回值就是对应resume传入的参数
    
      return "function return"  --当一个协同程序结束时,主函数返回值都将作为resume的返回值。
     end
     )
    
    print(coroutine.resume(co, 1, 2))  --调用resume后返回的内容,第一个值为true则表示没有错误,后面所有值都是对应yield传入的值
    print(coroutine.resume(co, 3, 4, 5))
    
    --[[
    输出:
    the first resume params: 1 2
    true yield return params
    
    resume params 3 4 5
    true function return
    ]]
    

    36、协程应用于生产者消费者模式(最好把代码运行一下,再去理解)

    function receive(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 = receive(prod)
      io.write(x, "\n")
     end
    end
    
    p = producer()
    f = filter(p)
    consumer(f)
    

    37、非抢先式多线程(协程):当一个协程运行时,无法从外部停止,只有协程显示的挂起(yield),才会停止。

    常用数据结构

    38、数组:以数字作为key的table,在lua中习惯用 1 作为数组起始,长度可变

    a = {}
    for i =1,10 do
     a[i] = 0
    end
    print(#a) --计算数组长度
    
    --直接创建并初始化数组
    a = {7, 6, 5, 5, 7, 8, 9, 0, 0, 5, 3}
    

    39、多维数组,可以用类似其它语言的方式表示多维,也可以利用一维数组表示。用稀疏矩阵表示一个图,table本身就是稀疏的,可以直接表示浪费内存。

    mt = {}
    for i=1,10 do
     mt[i] = {}
     for j=1,10 do
      mt[i][j] = 0
     end
    end
    

    遍历“稀疏矩阵”需要注意:一般使用pairs且只遍历那些非nil的元素。

    pairs 和 ipairs 的区别:pairs 可以遍历表中所有的key,而ipairs 只能遍历到表中出现的一个不是整数的key

    当然还有链表、队列、树、图等数据结构,这就不详细写了,这些东西和在其它语言里面是一样的

    40、字符串连接:先把每个字符串存到一个数组里面,然后用table.concat连接,比用(..)连接更快更省

    local a = {"A", "b", "C", "d", "E"} 
    local s = table.concat(a)
    

    数据持久化

    41、数据文件(读取):lua常常被用来做数据存取,在lua中,所谓的数据文件就是按一定格式定义的lua文件,把该“数据文件”加载进内存,就可以直接用lua代码解析了。

    local  count = 0
    function Entry(b)
     count = count + 1
     print("load data call : "..b[1])
    end
    
    --dofile("data")
    --data文件中就写如下的代码,这里为了简便,就直接把数据写在这里了。
    Entry{--注意数据文件里面的Entry必须提前定义,其实数据文件里面的Entry在调用一个名叫Entry的函数
     "A", "B", "C", "D", "E"
    }
    Entry{
     "f", "g", "h", "i", "j"
    }
    print("number of entries : "..count)
    

    42、数据持久化
    保存无“环”形table:

    function serialize(o)
     if type(o) == "number" then
      io.write(0)
     elseif type(o) == "string" then
      io.write(string.format("%q", o))
     elseif type(o) == "table" then
      io.write("{\n")
      for k,v in pairs(o) do
       io.write("  [")
       serialize(k);
       io.write("] = ")
       serialize(v)
       io.write(", \n")
      end
      io.write("}\n")
     else
      --其它情况
      error("can not serialize a"..type(o))
     end
    end
    
    serialize({a = 'A', b = 'Q', c = '1'})
    

    保存有“环”形table:

    43、元表:就是普通一个table,可以设置为其他表的元表,元表中可定义实现一系列的元方法

    t = {}
    t1 = {x = "a"}
    setmetatable(t, t1) --把 t1 设置为 t 的元表
    print(getmetatable(t)) --获得 t 的元表
    

    44、元方法:定义于元表中的那些重载的方法

    算术类元方法(__add(加法),__mul(乘法),__sub(减法),__div(除法),__unm(相反数),__mod(取模),__pow(幂)):

    local t = {}
    t.__add = function(a, b) --定义加法的元方法
     return a["value"] + b["value"]
    end
    
    local obj1 = {value = 1}
    setmetatable(obj1, t) --
    local obj2 = {value = 2}
    --setmetatable(obj1, t)
    
    print(obj1 + obj2) --加法的时候,会检查它们其中任意一个的元表,只要有名叫__add的元方法,就会调用它定义的加法运算
    

    关系类元方法(__eq(等于)、__lt(小于)、__le(等于)):

    字符串输出元方法(__tostring):
    local m = {}
    m.__tostring = function()
     return "meta function"
    end
    
    local a = {}
    setmetatable(a, m)
    
    print(a)
    

    保护元表:使用用户既不能看也不能修改集合的元表,定义字段 __metatable

    local m = {}
    m.__metatable = "not your business" --保护元表
    
    local a = {}
    setmetatable(a, m)
    
    print(getmetatable(a)) --not your business
    setmetatable(a, m) --cannot change protected metatable
    

    table访问的元方法:
    __index元方法:当访问一个table中不存在的字段时,解释器会去查找元表中名叫__index的元方法,如果没有该方法,返回nil,否则由这个元方法提供结果。

    local m = {}
    m.__index = function()
     return "index nil"
    end
    
    local a = {}
    setmetatable(a, m)
    
    print(a[1]) --index nil
    

    __newindex元方法:当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法,如果元表中有该元方法,就调用它而不执行赋值。

    相关文章

      网友评论

        本文标题:Lua语言入门(三)

        本文链接:https://www.haomeiwen.com/subject/ohwxyttx.html