function readOnly(t)
local proxy = {}
local mt = {
__index = t,
__newindex = function(t,k,v)
error("attempt to update a read-only table")
end
}
setmetatable(proxy,mt)
return proxy
end days = readOnly{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
print(days[])
days[] = "Noday"

—关于上面的只读表的运行过程解释

1:首先readOnly这个函数调用的说明,这个调用有点与其他语言不一样,参数没有放在圆括号中” 函数名() “,

而是直接跟了一个表的构造式,参看program in lua第五章 函数,最开始的前10句:

一个函数若只有一个参数,并且此参数是一个字面字符串或者是一个table构造式,那么圆括号是可有可无的.

days = readOnly{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}

2:readOnly(t) 的形参 t,接收了 {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday”}

那么相当于 t = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday”}

3:紧接着 local proxy = {} 是一个局部的表,且是空表,它的元表为mt,是因为 setmetatable(proxy,mt)这句话。

也就是说 proxy.__index = mt. __index这个字段是lua 为表内置的.

4:紧接着 return proxy 那么就相当于 days = proxy,记住 proxy是空表

5:print(days[1]) 相当于print(proxy[1]) ,但由于proxy[1]没有值,于是找它的元表 mt,而mt也没有 mt[1]对应的值,于是又找到__index 字段对应的值,于是就找到了之前t接收的匿名元表,然后就输出了Sunday,匿名元表就是{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday”}

6:当对其赋值时,同第5步一样,最终找到了__newindex, 而它的值是一个函数,于是执行了

error("attempt to update a read-only table”)

7:上面的分析过程,就是lua解释这个脚本的过程,我们想象成,自己写了一个函数,当它接收那样一段脚本时,是像上面那样执行这么一个逻辑,把这么一个逻辑用一个概念总结,称之为元表,这就是元表的内函.

8:那为什么要这样做呢?这个逻辑,实际上是面向对象语言中的,多态的逻辑。只不过像C++,这样的语言,把上面的这种寻找过程的代码,由编译器产生而已。多态是相对继承而言的,即父类指针,指向了子类的对象,在运行时发生的行为,与代码给我们的字面逻辑不一致.

9:lua通过元表,来模拟面象对象的多态特性。

--输出结果为:

--[[

Sunday

lua: d:/test.lua:6: attempt to update a read-only table

stack traceback:

[C]: in function 'error'

d:/test.lua:6: in function <d:/test.lua:5>

d:/test.lua:15: in main chunk

[C]: ?

]]—

//-------------------------接下来分析一下 program in lua 第十三章的 13.1“算术类的元方法”------------------

把代码里加了点打印语句,就好理解了,另外把for语句省掉的部分写完整了。这样对照结果,就不会迷糊了

对于初学者来说,原版书写的真是有点"不够厚道"。我看了N遍.才明白.不过省掉应该是为了少返回值,少执行一些代码,提高效率吧。

Set = {}
local mt ={}
function Set.new (l)
local set = {}
setmetatable(set, mt)
for _, v in ipairs(l) do
print("<",_,">","(",v,")")
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 print(k,res[k]) end
for k ,v in pairs(b) do res[k] = true print(k,res[k]) end
return res
end function Set.intersection (a,b)
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end function Set.tostring (set)
local l = {}
for e ,v in pairs(set) do
print(e,"|----|", v)
l[#l + ] = e
end
return "{" .. table.concat(l,", ") .. "}"
end function Set.print(s)
print(Set.tostring(s))
end s1 = Set.new{,,,,}
s2 = Set.new{,}
print(getmetatable(s1))
print(getmetatable(s2)) mt.__add = Set.union s3 = s1 +s2 print('-------')
print(s3)
print('-------') Set.print(s3) print(getmetatable("")) for n in pairs(_G) do print(n) end

lua 元表是个啥?的更多相关文章

  1. [转]LUA元表

    lua元表和元方法 <lua程序设计> 13章 读书笔记 lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在 ...

  2. 学习Lua setmetatable Lua 元表

    Lua 元表(Metatable) 在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作. 个人理解,这个相当于其他语言的继承,是把这个类的方法 ...

  3. Step By Step(Lua元表与元方法)

    Step By Step(Lua元表与元方法) Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表 ...

  4. lua元表与元方法

    lua中提供的元表(metatable)与元方法(metamethod)是一种非常重要的语法,metatable主要用于做一些类似于C++重载操作符式的功能. lua中提供的元表是用于帮助lua变量完 ...

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

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

  6. lua元表

    __index元方法:按照之前的说法,如果A的元表是B,那么如果访问了一个A中不存在的成员,就会访问查找B中有没有这个成员.这个过程大体是这样,但却不完全是这样,实际上,即使将A的元表设置为B,而且B ...

  7. <6>Lua元表和冒号 self

    Lua中没有像C.C++.JAVA中的类概念,面向对象等 ,但我们可以模拟出来 1. Lua中有个很重要的概念元表 设置元表setmetatable()函数  获取元表getmetatable()函数 ...

  8. lua元表学习

    a = {, } b= {, } vector2 = {} function vector2.Add(v1, v2) if(v1 == nil or v2 == nil)then return nil ...

  9. [转]lua元表代码分析

    http://lin-style.iteye.com/blog/1012138 版本整理日期:2011/4/21 元表其实就是可以让你HOOK掉一些操作的一张表. 表的定义在ltm.h/c的文件里.对 ...

  10. lua元表详解

    元表的作用 元表是用来定义对table或userdata操作方式的表 举个例子 local t1 = {1} local t2 = {2} local t3 = t1 + t2 我们直接对两个tabl ...

随机推荐

  1. python核心编程学习记录之Web编程

    cgi未完待续

  2. JWT笔记

    JWT是一个无状态登录的技术.所谓无状态,是指和传统的session技术相比,服务器端不需要存储用户的信息.在JWT技术中,agent向server请求一个Token. 这个Token由三部分组成,h ...

  3. linux中grep命令

    grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. grep常用用法 [root@www ~]# grep [-acinv] [--color=auto] '搜寻字 ...

  4. Tomcat 编码不一致导致乱码

    众所周知,Tomcat是一个基于HTTP协议的Java应用服务器(非Web服务器),也是一个Servlet容器. 一般我们会基于使用HTTP协议的Post或Get方法来传递内容或参数,中间会涉及一些编 ...

  5. UI_UITableView_搭建

    创建 tableView UITableViewStyle 有两种选择 #pragma mark - 创建 tableView - (void)createTableView { // 枚举类型共同拥 ...

  6. Java中的回调函数学习-深入浅出

    Java中的回调函数一般来说分为下面几步: 声明回调函数的统一接口interface A.包括方法callback(); 在调用类caller内将该接口设置为私有成员private A XXX; 在c ...

  7. Linux非阻塞IO(四)非阻塞IO中connect的实现

    我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ...

  8. 类的成员函数指针和mem_fun适配器的用法

    先来看一个最简单的函数: void foo(int a) { cout << a << endl; } 它的函数指针类型为 void (*)(int); 我们可以这样使用: v ...

  9. List of CentOS Mirrors

    From:https://www.centos.org/download/mirrors/ CentOS welcomes new mirror sites. If you are consideri ...

  10. c#关于int(或其他类型)的字段在对象初始化时默认初始化问题的解决方法

    问题: c#的wcf服务接口在后台通过自定义对象接收前台参数的时候,前台参数即使不传int类型的字段值,后台也会默认初始化为0,由于很多表示状态的int字段都是从0开始的,导致查询的时候有些不想参与查 ...