鍍金池/ 教程/ Java/ 元表
數(shù)據(jù)庫訪問
循環(huán)
數(shù)組
錯(cuò)誤處理
面向?qū)ο?/span>
調(diào)試
游戲開發(fā)
文件 I/O
變量
迭代器
Web 編程
模塊
函數(shù)
元表
協(xié)程
垃圾回收機(jī)制
標(biāo)準(zhǔn)庫
決策
數(shù)據(jù)類型
運(yùn)行環(huán)境
操作符
字符串
基本語法
概述

元表

正如其名,元表也是表。不過,將元表與表相關(guān)聯(lián)后,我們就可以通過設(shè)置元表的鍵和相關(guān)方法來改變表的行為。元方法的功能十分強(qiáng)大,使用元方法可以實(shí)現(xiàn)很多的功能,比如:

  • 修改表的操作符功能或?yàn)椴僮鞣砑有鹿δ埽ㄗg注:如果您學(xué)過 C++ 之類的面向?qū)ο蟮恼Z言,應(yīng)該比較好理解,其實(shí)它實(shí)現(xiàn)的是操作的重載)。
  • 使用元表中的 __index 方法,我們可以實(shí)現(xiàn)在表中查找鍵不存在時(shí)轉(zhuǎn)而在元表中查找鍵值的功能。

Lua 提供了兩個(gè)十分重要的用來處理元表的方法,如下:

  • setmetatable(table,metatable):此方法用于為一個(gè)表設(shè)置元表。
  • getmetatable(table):此方法用于獲取表的元表對象。

首先,讓我們看一下如何將一個(gè)表設(shè)置為另一個(gè)表的元表。示例如下:

mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)

上面的代碼可以簡寫成如下的一行代碼:

mytable = setmetatable({},{})

__index

下面的例子中,我們實(shí)現(xiàn)了在表中查找鍵不存在時(shí)轉(zhuǎn)而在元表中查找該鍵的功能:

mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return mytable[key]
    end
  end
})

print(mytable.key1,mytable.key2)

運(yùn)行上面的程序,我們可以得到如下的輸出結(jié)果:

value1  metatablevalue

接下來逐步解釋上面例子運(yùn)行的過程:

  • 表 mytable 為 {key = "values1"}
  • 為 mytable 設(shè)置了一個(gè)元表,該元表的鍵 __index 存儲(chǔ)了一個(gè)函數(shù),我們稱這個(gè)函數(shù)為元方法。
  • 這個(gè)元方法的工作也十分簡單。它僅查找索引 “key2”,如果找到該索引值,則返回 "metatablevalue",否則返回 mytable 中索引對應(yīng)的值。

上面的程序同樣可以簡化成如下的形式:

mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

__newindex

為元表添加 newindex 后,當(dāng)訪問的鍵在表中不存在時(shí),此時(shí)添加新鍵值對的行為將由此元方法(newindex)定義。下面的例子中,如果訪問的索引在表中不存在則在元表中新加該索引值(注意,是添加在另外一個(gè)表 mymetatable 中而非在原表 mytable 中。),具體代碼如下(譯注:請注意此處 __newindex 的值并非一個(gè)方法而是一個(gè)表。):

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "new  value 1"
print(mytable.key1,mymetatable.newkey1)

執(zhí)行上面的程序,我們可以得到如下的輸出結(jié)果:

value1
nil new value 2
new  value 1    nil

可以看出,在上面的程序中,如果鍵存在于主表中,只會(huì)簡單更新相應(yīng)的鍵值。而如果鍵不在表中時(shí),會(huì)在另外的表 mymetatable 中添加該鍵值對。
在接下來這個(gè)例子中,我們用 rawset 函數(shù)在相同的表(主表)中更新鍵值,而不再是將新的鍵添加到另外的表中。代碼如下所示:

mytable = setmetatable({key1 = "value1"}, {
  __newindex = function(mytable, key, value)
        rawset(mytable, key, "\""..value.."\"")

  end
})

mytable.key1 = "new value"
mytable.key2 = 4

print(mytable.key1,mytable.key2)

執(zhí)行上面的程序,我們可以得到如下的輸出結(jié)果:

new value   "4"

rawset 函數(shù)設(shè)置值時(shí)不會(huì)使用元表中的 newindex 元方法。同樣的,Lua 中也存的一個(gè) rawget 方法,該方法訪問表中鍵值時(shí)也不會(huì)調(diào)用 index 的元方法。

為表添加操作符行為

使用 + 操作符完成兩個(gè)表組合的方法如下所示(譯注:可以看出重載的意思了):

mytable = setmetatable({ 1, 2, 3 }, {
  __add = function(mytable, newtable)
    for i = 1, table.maxn(newtable) do
      table.insert(mytable, table.maxn(mytable)+1,newtable[i])
    end
    return mytable
  end
})

secondtable = {4,5,6}

mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print(k,v)
end

執(zhí)行上面的的程序,我們可以得到如下的輸出結(jié)果:

1   1
2   2
3   3
4   4
5   5
6   6

元表中 __add 鍵用于修改加法操作符的行為。其它操作對應(yīng)的元表中的鍵值如下表所示。

描述
__add 改變加法操作符的行為。
__sub 改變減法操作符的行為。
__mul 改變乘法操作符的行為。
__div 改變除法操作符的行為。
__mod 改變模除操作符的行為。
__unm 改變一元減操作符的行為。
__concat 改變連接操作符的行為。
__eq 改變等于操作符的行為。
__lt 改變小于操作符的行為。
__le 改變小于等于操作符的行為。

__call

使用 __call 可以使表具有像函數(shù)一樣可調(diào)用的特性。下面的例子中涉及兩個(gè)表,主表 mytable 和 傳入的實(shí)參表結(jié)構(gòu) newtable,程序完成兩個(gè)表中值的求和。

mytable = setmetatable({10}, {
  __call = function(mytable, newtable)
    sum = 0
    for i = 1, table.maxn(mytable) do
        sum = sum + mytable[i]
    end
    for i = 1, table.maxn(newtable) do
        sum = sum + newtable[i]
    end
    return sum
  end
})
newtable = {10,20,30}
print(mytable(newtable))

運(yùn)行上面的代碼,我們可以得到如下的輸出結(jié)果:

70

__tostring

要改變 print 語句的行為,我們需要用到 __tostring 元方法。下面是一個(gè)簡單的例子:

mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
        sum = sum + v
    end
    return "The sum of values in the table is " .. sum
  end
})
print(mytable)

運(yùn)行上面的代碼,我們可以得到如下的輸出結(jié)果:

The sum of values in the table is 60

如果你完全掌握了元表的用法,你就可以實(shí)現(xiàn)很多看上面很復(fù)雜的操作。如果不使用元表,就不僅僅是看上去很復(fù)雜了,而是真的非常復(fù)雜。所以,多做一些使用元表的練習(xí),并熟練掌握所有元表的可選項(xiàng),這會(huì)讓你受益匪淺。

上一篇:Web 編程下一篇:循環(huán)