Lua中metatable和__index的联系

可以参考 http://blog.csdn.net/xenyinzen/article/details/3536708

来源 http://blog.csdn.net/fishe_r/article/details/77530369

最近学习lua今天突然对metatable和__index之间的关系有点不清楚,上网查了下加深了对metatable的理解,记录一下

还是用代码来解释,下面有图解,metatable和__index主要用于继承相关,有两种方式:

test.lua

local test = {}

function test:new()
self.__index = self
return setmetable({}, self)
end function test:say()
print("111")
end local t1 = test:new()
t1.say() local t2 = t1:new()
t2.say() return test

test2.lua

local test2 = {}

test2.__index = test2

function test2:new()
return setmetatable({}, self) -- 这里的self 替换成 test2 试试
end function test2:say()
print("222")
end local t3 = test2:new()
t3.say() local t4 = t3:new()
t4.say() -- 这一步会报错 return test2

上面的代码test.lua中t1,t2都能访问到new和say方法,但是test2中只有直接通过test2:new()生成的对象(t3)才能访问new和say方法,而通过test2:new()生成的子对象生成的对象(t4)则访问不到new和say方法

要解释上述问题,首先要知道lua从table中查找一个key时的流程,当从表t中查找k时:

  1. t中是否有k,有则返回,无则第2步
  2. t是否有metatable,无则返回nil,有则第3步
  3. t的metatable中是否有__index方法,无则返回nil,有则查找 __index对应的table或者方法

所以我们一步步分析test.lua中的代码:

local test = {}

function test:new()
...
end function test:say()
...
end

这一句就是创建了一个table,我们用方块表示table则就是下面这样: 

接下来实例化一个对象:

local t1 = test:new()

这里调用test:new(),相当于test.new(test),函数中的self为test,所以这一步改变了test表,结果用图表示为: 

图中椭圆表示__index函数,__index指向test自身,可以看到这时test表和上面不一样,而t1是一个新生成的表,这个表的metable为test,但是t1本身没有其他内容

再来看最后一步

local t2 = t1:new()

此时结果为: 

这一步new函数中的的self为t1,所以最后改变了t1的__index指向t1,生成新的表t2的metatable为t1,由于t1和t2都有metatable并且metatable中都有__index方法所以都可以访问test中的new和say方法,即使它们自身没有这两个方法

再来看test2.lua中有什么不同,同理按照上面的分析有三个图,就不一一解释了 

唯一不同的地方就在于__index方法的设置,在test2.lua中 __index只在test2表中设置,在继承过程中,并没有设置对应的__index方法,所以t3可以访问到new和say,但是t4则不可以

不过由此引出我一个问题,我们可以看到lua中查找不存在的k时,最终起作用的其实是__index方法,类似的还有操作符元方法等,但是却要先找metatable,然后找metatable里面的这些元方法,metatable在这里是相当于一个代理一样的作用,那么为什么不能直接在自身的表中设置,为什么要有metatable这个中间表??

猜想一:可能是模块化的考虑也就是把这些元方法集中在一起

  • 但是lua中有一个常用的用法就是 __index指向自身,上述例子就是这样,那么这个table里面本身就有元方法和自己的数据,而lua也没有说不推荐这么做,所以也不符合模块化的考虑

猜想二:可能是为了多个table方便共享同一个metatable

  • 问题是直接在自身table中设置__index指向同一个metatable也可以达到这种效果

猜想三:刚刚想到如果没有metatable的话,直接用__index指向要设置的元表,那么如果我想把自身作为基类,用__index指向自身,就会陷入死循环

  • 不知道是不是因为这点才引入了metatable这么一个中间代理

所以不清楚这部分的设计理念是什么,如果有知道的可以留言下

Lua中metatable和__index的联系的更多相关文章

  1. Lua中的metatable详解

    转自:http://www.jb51.net/article/56690.htm Lua 中 metatable 是一个普通的 table,但其主要有以下几个功能: 1.定义算术操作符和关系操作符的行 ...

  2. lua学习:lua中“类”的实现

    在之前的面试遇到考用lua实现类的题目.现在就补补这块知识点. 我们都知道Lua中的table是一个对象.拥有状态,拥有self,拥有独立于创建者和创建地的生命周期. 一个类就是一个创建对象的模具.L ...

  3. lua 14 metatable (类似操作符重载)

    转自:http://www.runoob.com/lua/lua-metatables.html 感性认识: “Lua中Metatable这个概念, 国内将他翻译为元表. 元表为重定义Lua中任意一个 ...

  4. 【Lua】Lua中__index与元表(转)

    转载于:http://blog.csdn.net/xocoder/article/details/9028347 Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Value对,如 ...

  5. lua中的metatable和metamethod

    --元表和元方法给lua里的值设定一些操作,让我们可以对这些操作自定义 --创建一个新的table变量时,它是不存在元表的 --在Lua中,只能设置table的元表,其他类型的值的元表,只能通过C代码 ...

  6. Lua中的元表(metatable)、元方法(metamethod)详解

    在第一次看见这两样东西的时候,可能会觉得它很深奥,但其实很好理解,虽然实际上它可能真的很深奥.(小若:停!滚粗.) 1.知道为什么1 + 1 = 2吗? 为什么在Lua中,1+1会等于2呢?(小若:难 ...

  7. lua元表Metatable

    Lua 中的每个值都可以用一个 metatable. 这个 metatable 就是一个原始的 Lua table , 它用来定义原始值在特定操作下的行为. 你可以通过在 metatable 中的特定 ...

  8. lua 中的面向对象

    lua 是一种脚步语言,语言本身并不具备面向对象的特性. 但是我们依然可以利用语言的特性,模拟出面向对象的特性. 面向对象的特性通常会具备:封装,继承,多态的特性,如何在lua中实现这些特性,最主要的 ...

  9. Lua中的weak表——weak table

    弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的.弱表的定义是:A weak table is a table whose elements are weak ref ...

随机推荐

  1. [UIKit学习]06.懒加载,模型,自定义代码段,重写构造方法

    懒加载 在get中加载,且只加载一次 - (NSArray *)shops { if (_shops == nil) { NSString *file = [[NSBundle mainBundle] ...

  2. 详细解读-this-关键字在全局、函数、对象、jQuery中的基础用法!

    一.前言 1. Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的设计模式来实现面向对象的编程,其 ...

  3. ElasticSearch入门(3) —— head插件

    #### 安装ES head插件 具体请参考github地址:https://github.com/mobz/elasticsearch-head 使用 安装Install # 在线安装head插件 ...

  4. ObjectSNMP

    下面的例子,就是使用ObjectSNMP获取RFC1213-MIB的例子:其中的system和ifTable对象就是对应的SNMPMIB中的system组合interface中的ifTable表. p ...

  5. Milk Patterns poj3261(后缀数组)

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9274   Accepted: 4173 Cas ...

  6. hdu1671字典树

    Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. spring 内部工作机制(一)

    Spring内部机制的内容较多,所以打算多分几个阶段来写. 本章仅探索Spring容器启动做了哪些事: 前言: 都说Spring容器就像一台构造精妙的机器,此话一点不假,我们通过配置文件向机器传达控制 ...

  8. Python自学笔记-logging模块详解

    简单将日志打印到屏幕: import logging logging.debug('debug message') logging.info('info message') logging.warni ...

  9. 如何在Windows系统中配置Mysql群集(Mysql Cluster)

    MySQL群集技术在分布式系统中为MySQL数据提供了冗余特性,增强了安全性,使得单个MySQL服务器故障不会对系统产生巨大的负面效应,系统的稳定性得到保障. Mysql群集(Cluster)简介 M ...

  10. 部署LAMP+NFS实现双Web服务器负载均衡

    一.需求分析 1.前端需支持更大的访问量,单台Web服务器已无法满足需求了,则需扩容Web服务器: 2.虽然动态内容可交由后端的PHP服务器执行,但静态页面还需要Web服务器自己解析,那是否意味着多台 ...