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. junit initializationError和找不到或无法加载主类

    今天在做Junit测试的时候 出现了initialzationError , 在网上查找,一般都是因为Jar 包冲突或者缺少Jar包导致的, 但是我的其他方法是可以使用Junit 的, 所以感觉应该跟 ...

  2. NameError: name 'messagebox' is not defined 错误处理

    写了段代码,想在按下button的时候跳个提示框出来,调试的时候提示了messagebox未定义 from tkinter import * def test_show(): messagebox.s ...

  3. node.js express mvc轻量级框架实践

    本文记录的是笔者最近抽私下时间给朋友做的一个时时彩自动下注系统,比较简单,主要也是为了学习一下node.js. 其实逻辑没什么可以深谈的,主要是想说说这套代码结构.结构如下图: js的代码比较难以维护 ...

  4. MySQL主从同步和读写分离的配置

    主服务器:192.168.1.126 从服务器:192.168.1.163 amoeba代理服务器:192.168.1.237 系统全部是CentOS 6.7 1.配置主从同步 1.1.修改主服务器( ...

  5. Linux学习——shell编程之正则表达式和字符处理命令

    shell编程之正则表达式 一 正则表达式 1 什么是正则表达式 正则表达式用于描述字符排列和匹配模式的一种语法规则.它主要用于字符串的模式分隔.匹配.查找及替换操作. 2 shell编程之正则表达式 ...

  6. Linux学习——shell编程之运算符

    shell编程之运算符 一:shell中常见算术运算符号和优先级 二:算术运算符 Shell 变量:是弱类型!不能进行加减乘除!比较麻烦! 例子 :shell变量弱类型 a=11 b=22 echo ...

  7. HDFS源码分析之NameNode(1)————启动过程

    源码:2.8.0 入口类:org.apache.hadoop.hdfs.server.namenode.NameNode main方法会调用createNameNode 创建 NameNode 实例, ...

  8. Python 获取当前脚本文件路径目录

    # -*- coding: cp936 -*- import sys,os # 获取脚本文件的当前路径 def cur_file_dir(): # 获取脚本路径 path = sys.path[0] ...

  9. Hibernate操作数据库的回调机制--Callback

     1:一般情况下,在使用Hibernate Session存取数据库的代码中,基本上大部分是相同的,如下两个方法所示, //查询Teacher操作 ublic Teacher getTeacher ...

  10. Jquery滚动到页面底部自动Ajax加载图文列表,类似图片懒加载效果,带加载效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...