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  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM