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. String类的一些转换功能(6)

    1:把字符串转换成字节数组 getBytes() 如: String s = "你好啊!" //编码 byte [] arr = s.getBytes();//这里默认编码格式是g ...

  2. Linux 安装Anaconda 4.4.0

    安装步骤参考了官网的说明:https://docs.anaconda.com/anaconda/install/linux.html 具体步骤如下:  1.在官网下载地址 https://www.an ...

  3. 实例讲解webpack的基本使用第一篇

    更新文章不容易,尤其是更新高质量的文章更加不易,因此为了节约时间,闲话就不多说了.关于webpack的介绍,webpack是用来干嘛的,这些基础概念性的东西,就不在此赘述,下面直接开始正题. webp ...

  4. 【JVM命令系列】jstack

    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使 ...

  5. Eddy's爱好 hdu2204

    Eddy's爱好 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  6. PHP浮点型(float)转换为整形(int)/round()保留小数点后几位

    round(x,y); x:需要转换的变量 y:保留几位小数 <?php echo round(3.112312321) //输出3 echo round(3.112312321,3) //输出 ...

  7. 【DDD】领域驱动设计实践 —— Domain层实现

    本文是DDD框架实现讲解的第三篇,主要介绍了DDD的Domain层的实现,详细讲解了entity.value object.domain event.domain service的职责,以及如何识别出 ...

  8. 未能写入输出文件“c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root

    打开服务器系统c盘,打开window, 右键temp 属性 安全 编辑 添加IIS_IUSRS 用户控制权限添加修改和写入权限即可.这是Windows Server 2008 R2 标准版 SP1 6 ...

  9. Block使用的简单总结

    一.Block简单的使用 1.block当作参数来传递 如下定义一个没有返回值无参数的block,并把它作为参数,让系统调用,注意:这里是系统在调用,不是我们调用 那么为什么需要把block当作参数去 ...

  10. Java面向对象 IO (四)

     Java面向对象  IO  (四) 知识概要:                 (1)打印流 (2)序列流 SequenceInputStream (3)ObjectInputStream与Ob ...