lua 元表是个啥?

 1 function readOnly(t)
 2     local proxy = {}
 3     local mt = {
 4         __index = t,
 5         __newindex = function(t,k,v)
 6             error("attempt to update a read-only table")
 7         end
 8     }
 9     setmetatable(proxy,mt)
10     return proxy
11 end
12 
13 days = readOnly{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
14 print(days[1])
15 days[2] = "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 + 1] = e
  end
  return "{" .. table.concat(l,", ") .. "}"
end

function Set.print(s)
  print(Set.tostring(s))
end

  
s1 = Set.new{10,20,30,40,}
s2 = Set.new{30,1}
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  

 

posted on 2015-02-10 16:25  EarlyBird  阅读(3523)  评论(0编辑  收藏  举报

导航