lua元表和元方法 《lua程序设计》 13章 读书笔记-阿里云开发者社区

开发者社区> 技术小阿哥> 正文

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内存

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
论文笔记之:Action-Decision Networks for Visual Tracking with Deep Reinforcement Learning
论文笔记之:Action-Decision Networks for Visual Tracking with Deep Reinforcement Learning  2017-06-06  21:43:53      这篇文章的 Motivation 来自于 MDNet:         本文所...
1628 0
论文笔记之:DualGAN: Unsupervised Dual Learning for Image-to-Image Translation
DualGAN: Unsupervised Dual Learning for Image-to-Image Translation2017-06-12  21:29:06       引言部分:   本文提出一种对偶学习模式的 GAN 网络结构来进行 image to image translation。
1726 0
《Akka应用模式:分布式应用程序设计实践指南》读书笔记3
分布式领域驱动设计   DDD领域驱动设计,应该就是一种系统设计的方法论,可以知道人们设计软件。其实老外就喜欢总结一些方法论用于指导实践,这一点还是很重要的。 DDD概述   DDD是一套关于软件架构的指导原则。
1768 0
《Akka应用模式:分布式应用程序设计实践指南》读书笔记2
Akka简介   Akka是什么:“Akka是在JVM上构建高并发、分布式、弹性消息驱动应用的开源工具包”。弹性意味着要积极响应失败情况,从失败中恢复的能力。   其实Akka的定义很符合响应式领域模型,这个模型有几个基本特征:   1、弹性。
1850 0
《JavaScript高级程序设计(第3版)》阅读笔记
第6章 面向对象的程序设计 6.2 创建对象 6.2.1 工厂模式 JavaScript创建对象(一)—— 工厂模式 6.
833 0
13694
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载