• lua元表和元方法 《lua程序设计》 13章 读书笔记


    lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表。lua在创建table时不会创建元表。

    t = {}
    print(getmetatable(t))  --显示过元表 此时是nil
    
    --可以用setmetatable来设置或修改任何table的元表
    t1 = {}
    setmetatable(t,t1)
    assert(getmetatable(t) == t1)

    任何table可以作为任何值的元表,而一组相关的table可以共享一个通用的元表,此元表描述了一个共同的行为。一个tabel甚至可以作为它自己的元表,用于描述其特有行为。

    在lua中,只能设置table的元表。要设置其它类型的元表,必须通过C代码来完成

    print(getmetatable("hi"))  --005DECD8 说明字符串有元表
    print(getmetatable(10))  --number没有元表

    13.1  算术类的元方法

    Set = {}  --集合
    
    local mt = {}  --集合元表
    
    --根据参数列表中的值创建一个新的集合
    function Set.new(l)
        local set = {}
        setmetatable(set,mt)  --指定 table set的元表为mt
        for k,v in ipairs(l) do
            set[v] = true    --注意,是拿索来当数据用的
        end
        return set
    end
    function Set.union(a,b)
        local res = Set.new{}
        for k,v in pairs(a) do res[k] = true end
        for k,v in pairs(b) do res[k] = true end
        return res
    end
    
    function Set.intersection(a,b)
        local res = Set.new{}
        for k,v in pairs(a) do
            if b[k] then
                res[k] = true
            end
        end
        return res
    end
    
    function Set.tostring(set)
        local l = {}
        for k,v in pairs(set) do
            l[#l + 1] = k
        end
        return "{" .. table.concat(l,", ") .. "}"
    end
    
    function Set.print(s)
        print(Set.tostring(s))
    end
    
    
    --将元方法加入元表
    mt.__add = Set.union   --指定加号为求并集的方法
    mt.__mul = Set.intersection  --指定乘号为交集的方法
    
    s1 = Set.new{11,22,31,44,56}
    s2 = Set.new{66,33,22,31}
    s3 = s1 + s2 --求并集   
    Set.print(s3) --输出 {11, 31, 66, 22, 33, 56, 44}
    s4 = s1 * s2 --求交集
    Set.print(s4) --输出 {31, 22}

    13.2 关系类元方法

    关系是指 __eq(等于)、__lt(小于)等

    mt.__le = function(a,b)
         for k in pairs(a) do
            if not b[k] then  return false end
         end
         return true
    end
    
    mt.__lt = function(a,b)
        return a<=b and not (b<=a)
    end
    
    mt.__eq = function(a,b)
        return a<=b and b<=a
    end
    
    ss1 = Set.new{2,4}
    ss2 = Set.new{4,10,2}
    print(ss1<=ss2)  --true
    print(ss1<ss2)   --true
    print(ss1>=ss1)  --true
    print(ss1>ss1)   --false
    print(ss1 == ss2*ss1)  --true

    13.3 库定义的元方法

    tostring是一个典型的实例。它能将各种类型的值表示为简单的文本格式

    print({}) ----table: 003ECEF0

    函数总是调用tostring来格式化输出。当格式化任意值时,tostring会检测该值是否有一个 __tostring元方法。如果有,他就调用这个方法用来作为tostring的返回值

    在集合实例中,我们定议了将任命表示为字符串的方法,我们可以设置元表的__tostring字段

    mt.__tostring = Set.tostring
    sstext = Set.new{33,55,6666}
    print(sstext)  --{55, 33, 6666}

    假设想要保护集合的元表,使用户即不能看也不能修改集合的元表。那么就需要用到__metatable。当设置了该字段时,getmetatable就会返回这个字段的值,而setmetatable会引发一个错误

    mt.__metatable = "not your business"
    sstext1 = Set.new{}  
    print(getmetatable(sstext1))  --not your business
    setmetatable(s1,{})

    13.4 table 访问的元方法

    13.4.1 __index元方法

    当访问一个table中不存在的字段中时,如果这个字段不存在得到nil,但是如果这个table有一个元方法__index那么如果没有这个字段,就由这个元方法来提供结果

    Window = {}
    
    Window.prototype = {x=0,y=0,width = 100,height = 100}
    Window.mt = {}
    
    function Window.new(o)
        setmetatable(o,Window.mt)
        return o
    end
    
    --现在定义一个元方法
    Window.mt.__index = function(table,key)
        return Window.prototype[key]
    end
    
    
    w = Window.new{x=10,y=20}
    print(w.width)  -- 100 window实际上没有width这个字段

    __index元方法还可以是一个table

    13.4.2  __newindex元方法

    与__index不同的是__index是在查询的时候用的而_newindes是在更新的时候用的

    13.4.3具有默认值的table

    以下代码为table设置默认值

    function setDefault(t,d)
        local mt = {__index = function() return d end}
        setmetatable(t,mt)
    end

    13.4.4 跟踪table的访问

    __index和__newindex都是在table中没有所需的index才发挥作用。因为只有table保持空才能捕捉到所有对他的访问,为了监视一个table的所有访问就得为真正的 table 创建一个代理

    t_src = {}  --要跟踪的表
    local _t = t_src
    
    t = {} --创建代理
    
    --创建元表
    local mt = {
        __index = function(t,k)
            print("*access to element "  .. tostring(k))
            return _t[k]
        end,
        __newindex = function(t,k,v)
            print("*update of element " .. tostring(k) .. " to " .. tostring(v))
            _t[k] = v
        end
    }
    setmetatable(t,mt)
    
    t[2]  = "hello"  -- *update of element 2 to hello
    print(t[2])  --*access to element 2

    13.4.5 只读的table

    只读table与上一节跟踪table类似,是通过__newindex来限制修改table内存

  • 相关阅读:
    day 21 01 序列化模块和模块的导入的复习以及包的初识
    day 20 02 模块的导入
    Shell从入门到精通进阶之三:表达式与运算符
    Shell从入门到精通进阶之二:Shell字符串处理之${}
    shell从入门到精通进阶之一:Shell基础知识
    容器平台自动化CI/CD流水线实践之一:环境概述
    什么是DevOps?
    kubernetes进阶之七:Service
    kubernetes进阶之六:StatefulSet & DaemonSet
    kubernetes进阶之五:Replication Controller&Replica Sets&Deployments
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/3429220.html
Copyright © 2020-2023  润新知