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這個函數調用的說明,這個調用有點與其餘語言不同,參數沒有放在圓括號中」 函數名() 「,lua

而是直接跟了一個表的構造式,參看program in lua第五章 函數,最開始的前10句:spa

   一個函數若只有一個參數,而且此參數是一個字面字符串或者是一個table構造式,那麼圓括號是無關緊要的.
指針

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

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

  那麼至關於 t = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday}blog

3:緊接着 local proxy = {} 是一個局部的表,且是空表,它的元表爲mt,是由於 setmetatable(proxy,mt)這句話。繼承

  也就是說 proxy.__index = mt. __index這個字段是lua 爲表內置的.ip

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  
相關文章
相關標籤/搜索