美文网首页
初探 lua 的唯一数据结构 table

初探 lua 的唯一数据结构 table

作者: OOM_Killer | 来源:发表于2019-06-22 17:02 被阅读0次

    在lua的世界中是只有一种数据结构的,那就是table。
    而 table 做了在其他语言中,高级特性该做的所有事情。

    table 中的数组和hash

    这个是比较诡异的一种操作。没错,hash和数组在一起。举个例子

    local color = {first="red","blue",third="green","yellow"}
    print(color["first"])   -- red
    print(color[1])         -- blue
    print(color[2])         -- yellow
    print(color)            -- table: 0x41d99d48
    

    当取下标时,只取出数组部分,当取键时,就是去取hash部分。
    而table本身如果打印的话,他只是一个地址。

    lua 的数组下标是从1开始的,这点需要注意了。

    而遍历他们,lua又提供了两个方法,就是ipair和pair。

    local color = {first="red","blue",third="green","yellow"}
    for k,v in ipairs(color) do 
        print(k,v)
    end
    -- 1       blue
    -- 2       yellow
    
    for k,v in pairs(color) do 
        print(k,v)
    end
    
    -- 1       blue
    -- 2       yellow
    -- third   green
    -- first   red
    

    table 的库函数

    • table.getn 获得table的长度
      对于一个序列,其元素个数是getn或者一元操作符 # 。其取的长度都是数组的。
      且其操作是O(N)的,所以尽量在长度很长的情况下避免使用。
    local color = {first="red","blue",third="green","yellow","black"}
    print(table.getn(color))  -- 3
    print(#color)             -- 3
    
    • table.remove 删除指定元素
      删除元素,只是说删除 数组部分,也就是使用下标去删除的。
    local color = {first="red","blue",third="green","yellow","black"}
    table.remove(color,1)
    for k,v in pairs(color) do 
        print(k,v)
    end
    -- 1       yellow
    -- 2       black
    -- third   green
    -- first   red
    

    如果是删除 hash 部分的话就是 将指定的 元素设置成nil。同时,这样也是对内存的释放。

    local color = {first="red","blue",third="green","yellow","black"}
    table.remove(color,1)
    color.first = nil
    for k,v in pairs(color) do 
        print(k,v)
    end
    -- 1       yellow
    -- 2       black
    -- third   green
    
    • table.concat 元素拼接
      按照此方式,把table中的元素拼接起来,同样的,还是针对的是一个table中的数组部分。
    local color = {first="red","blue",third="green","yellow","black"}
    print(table.concat(color,","))
    -- blue,yellow,black
    print(table.concat(color,",",2))
    -- yellow,black
    

    中间的“,”是指将 数组中的元素以什么为分割符分割。如果最后还跟着数字,则指的是取该数字以后的元素。

    • table.insert 插入一个元素
      同样,这是对数组操作的了。但是insert的插入性能不乐观,如果不是指定下标去插入元素的话,那么每次需要调用Luajit的 lj_table_len 来获取数组的长度。以便插入队尾。
      所以在热代码处减少对insert的使用
    local color = {first="red","blue",third="green","yellow","black"}
    table.insert(color,1,"orange")
    for k,v in pairs(color) do
        print(k,v)
    end
    
    • table.new 新建一个table
      这是luajit的table扩展函数。用来新建table。这个函数会预先分配好指定数组和hash的空间大小。而不是在插入元素时自增长
      table.new(narray,nhash) 正是这个含义。
      因为自增长是一个代价非常高的操作。,会涉及到空间分配,resize和rehash等。
      因为是扩展出来的,所以使用的时候需要require一下。
    local new_tab = require "table.new" -- 需要luajit-2.1.0-beta3
    
    local t = new_tab(10,5)
    for i = 1,10 do
        t[i] = i
    end
    
    • table.clear 清空table
      这个同样是函数 table.clear() 里面的函数,用来清空某个table里面的所有数据。但并不会释放数组和hash所占用的内存。
      所以,在循环利用lua table时比较有效。可以避免反复的创建和销毁。
    local clear_tab = require "table.clear" -- 需要luajit-2.1.0-beta3
    
    local color = {first = "red", "blue", third = "green", "yellow"}
    clear_tab(color)
    for k,v in pairs(color) do 
        print(k,v)
    end
    

    元表

    元表(metatable)。元表是Lua中独有的概念,在实际的项目中,就是靠元表来对lua作面向对象编程的,在几乎所有的lua-resty-* 库中,都有他的身影。
    最重要的函数辅助元表的处理。

    • setmetatable(table,metatable): 对指定表设置元表,如果元表中存在 _metatable 键值,setmetatable会失败。
    • getmetatable(table),用于获取table的元素。

    类似python中的魔术方法,lua在这方面也有类似的做法。

    • __index 元方法
      __index 是元表中最常用的键值。当通过键访问表时,如果这个键没有值,则会寻找该元表的__index值。
    local v = { bar = 1 }
    t = setmetatable({}, { __index = v})
    print(t.bar)
    -- 1
    
    • __newindex 元方法
      该方法对表进行更新,_index 用来对表访问,当给表一个不存在的索引的时候,解释器会查找__newindex 元方法。
    local t = {}
    myt = setmetatable({k1 = "v1"}, {__newindex = t})
    
    print(myt.k1)
    -- v1
    
    myt.k2 = "v2"
    print(myt.k2,t.k2)
    -- nil v2
    
    myt.k1 = "new_v1"
    print(myt.k1,t.k1)
    -- new_v1 nil
    
    • __tostring 元方法
      __tostring 元方法是用来改变一个表的输出行为。
      比如
    local t = { 
        major = 5,
        minor = 3,
        patch = 102
    }
    myt = setmetatable(t, {
        __index = { name = "lua" },
        __tostring = function (t)
            return string.format( "%s version is %d.%d.%d",t.name,t.major,t.minor,t.patch )
        end
    })
    
    print(tostring(myt))
    - lua version is 5.3.102
    
    • __call 元方法
      可以让表像方法一样被调用。
    local version = { 
        name = "lua",
        major = 5,
        minor = 3,
        patch = 102
    }
    
    local function print_version(t)
        print(string.format( "%s version is %d.%d.%d",t.name,t.major,t.minor,t.patch ))
    end
    
    version  = setmetatable( version, { __call = print_version })
    
    version()
    

    面向对象

    面向对象是众多编程语言的所支持的。
    其主要特点有:

    1. 封装:能把一个实体的信息,功能装入一个变量或对象里。
    2. 继承:在不改动原有方法的基础上,对其进行扩充。
    3. 多态:在同一操作作用于不同的对象时。可以有不同的解释。
    4. 抽象: 简化复杂现实问题的解决。
    -- Meta class
    Rectangle = {
        area    = 0,
        length  = 0,
        breadth = 0,
    }
    
    function Rectangle:new ( o,length,breadth )
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        self.length  = length or 0
        self.breadth = breadth or 0
        self.area    = length * breadth
        return o
    end
    
    function Rectangle:printArea()
        print("矩形面积为 ",self.area)
    end
    
    -- 创建对象
    r = Rectangle:new(nil,10,20)
    
    -- 访问属性
    print("矩形的长为",r.length)
    -- 矩形的长为      10
    
    -- 访问成员函数
    r:printArea()    -- 或者写成 r.printArea(r)  用 :号表示是一个语法糖
    -- 矩形面积为      200
    

    相关文章

      网友评论

          本文标题:初探 lua 的唯一数据结构 table

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