亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Lua中的metatable詳解

2024-07-21 23:04:16
字體:
來源:轉載
供稿:網友

Lua 中 metatable 是一個普通的 table,但其主要有以下幾個功能:

1.定義算術操作符和關系操作符的行為
2.為 Lua 函數庫提供支持
3.控制對 table 的訪問

Metatables 定義操作符行為

Metatable 能夠被用于定義算術操作符和關系操作符的行為。例如:Lua 嘗試對兩個 table 進行加操作時,它會按順序檢查這兩個 table 中是否有一個存在 metatable 并且這個 metatable 是否存在 __add 域,如果 Lua 檢查到了這個 __add 域,那么會調用它,這個域被叫做 metamethod。

Lua 中每個 value 都可以有一個 metatable(在 Lua 5.0 只有 table 和 userdata 能夠存在 metatable)。每個 table 和 userdata value 都有一個屬于自己的 metatable,而其他每種類型的所有 value 共享一個屬于本類型的 metatable。在 Lua 代碼中,通過調用 setmetatable 來設置且只能設置 table 的 metatable,在 C/C++ 中調用 Lua C API 則可以設置所有 value 的 metatable。默認的情況下,string 類型有自己的 metatable,而其他類型則沒有:

 

復制代碼 代碼如下:

print(getmetatable('hi')) --> table: 003C86B8
print(getmetatable(10))  --> nil

 

Metamethod 的參數為操作數(operands),例如:

 

復制代碼 代碼如下:

local mt = {}
function mt.__add(a, b)
    return 'table + ' .. b
end
local t = {}
setmetatable(t, mt)
print(t + 1)

 

每個算術操作符有對應的 metamethod:

 

+ __add
* __mul
- __sub
/ __div
- __unm (for negation)
% __mod
^ __pow

 

對于連接操作符有對應的 metamethod:__concat

同樣,對于關系操作符也都有對應的 metamethod:

 

== __eq
< __lt
<= __le

 

其他的關系操作符都是用上面三種表示:
a ~= b 表示為 not (a == b)
a > b 表示為 b < a
a >= b 表示為 b <= a

和算術運算符不同的是,關系運算符用于比較擁有不同的 metamethod(而非 metatable)的兩個 value 時會產生錯誤,例外是比較運算符,擁有不同的 metamethod 的兩個 value 比較的結果是 false。

不過要注意的是,在整數類型的比較中 a <= b 可以被轉換為 not (b < a),但是如果某類型的所有元素并未適當排序,此條件則不一定成立。例如:浮點數中 NaN(Not a Number)表示一個未定義的值,NaN <= x 總是為 false 并且 x < NaN 也總為 false。

為 Lua 函數庫提供支持

Lua 庫可以定義和使用的 metamethod 來完成一些特定的操作,一個典型的例子是 Lua Base 庫中 tostring 函數(print 函數會調用此函數進行輸出)會檢查并調用 __tostring metamethod:

 

復制代碼 代碼如下:

local mt = {}
mt.__tostring = function(t)
    return '{' .. table.concat(t, ', ') .. '}'
end
 
local t = {1, 2, 3}
print(t)
setmetatable(t, mt)
print(t)

 

另外一個例子是 setmetatable 和 getmetatable 函數,它們定義和使用了 __metatable 域。如果你希望設定的 value 的 metatable 不被修改,那么可以在 value 的 metatable 中設置 __metatable 域,getmetatable 將返回此域,而 setmetatable 則會產生一個錯誤:

 

復制代碼 代碼如下:

mt.__metatable = "not your business"
local t = {}
setmetatable(t, mt)
print(getmetatable(t)) --> not your business
setmetatable(t, {})
    stdin:1: cannot change protected metatable

 

看一個完整的例子:

 

復制代碼 代碼如下:

Set = {}
 
local mt = {}
 
function Set.new(l)
    local set = {}
    -- 為 Set 設置 metatable
    setmetatable(set, mt)
    for _, v in ipairs(l) do set[v] = true end
    return set
end
 
function Set.union(a, b)
    -- 檢查 a b 是否都是 Set
    if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
        -- error 的第二個參數為 level
        -- level 指定了如何獲取錯誤的位置
        -- level 值為 1 表示錯誤的位置為 error 函數被調用的位置
        -- level 值為 2 表示錯誤的位置為調用 error 的函數被調用的地方
        error("attempt to 'add' a set with a not-set value", 2)
    end
    local res = Set.new{}
    for k in pairs(a) do res[k] = true end
    for k in pairs(b) do res[k] = true 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
 
mt.__add = Set.union
mt.__mul = Set.intersection
 
mt.__tostring = function(s)
    local l = {}
    for e in pairs(s) do
        l[#l + 1] = e
    end
    return '{' .. table.concat(l, ', ') .. '}'
end
 
mt.__le = function(a, b)
    for k in pairs(a) do
        if not b[k] then return false end
    end
    return true
end
 
mt.__lt = function(a, b)
    return a <= b and not (b <= a)
end
 
mt.__eq = function(a, b)
    return a <= b and b <= a
end
 
local s1 = Set.new({1, 2, 3})
local s2 = Set.new({4, 5, 6})
print(s1 + s2)
print(s1 ~= s2)

 

控制 table 的訪問

__index metamethod

在我們訪問 table 的不存在的域時,Lua 會嘗試調用 __index metamethod。__index metamethod 接受兩個參數 table 和 key:

復制代碼 代碼如下:

local mt = {}
mt.__index = function(table, key)
    print('table -- ' .. tostring(table))
    print('key -- ' .. key)
end
 
local t = {}
setmetatable(t, mt)
local v = t.a

 

__index 域也可以是一個 table,那么 Lua 會嘗試在 __index table 中訪問對應的域:

 

復制代碼 代碼如下:

local mt = {}
mt.__index = {
    a = 'Hello World'
}
 
local t = {}
setmetatable(t, mt)
print(t.a) --> Hello World

 

我們通過 __index 可以容易的實現單繼承(類似于 JavaScrpit 通過 prototype 實現單繼承),如果 __index 是一個函數,則可以實現更加復雜的功能:多重繼承、caching 等。我們可以通過 rawget(t, i) 來訪問 table t 的域 i,而不會訪問 __index metamethod,注意的是,不要太指望通過 rawget 來提高對 table 的訪問速度(Lua 中函數的調用開銷遠遠大于對表的訪問的開銷)。

__newindex metamethod

如果對 table 的一個不存在的域賦值時,Lua 將檢查 __newindex metamethod:

1.如果 __newindex 為函數,Lua 將調用函數而不是進行賦值
2.如果 __newindex 為一個 table,Lua 將對此 table 進行賦值

如果 __newindex 為一個函數,它可以接受三個參數 table key value。如果希望忽略 __newindex 方法對 table 的域進行賦值,可以調用 rawset(t, k, v)

結合 __index 和 __newindex 可以實現很多功能,例如:

1.OOP
2.Read-only table
3.Tables with default values

Read-only table

復制代碼 代碼如下:

function readOnly(t)
    local proxy = {}
    local mt = {
        __index = t,
        __newindex = function(t, k, v)
            error('attempt to update a read-only table', 2)
        end
    }
    setmetatable(proxy, mt)
    return proxy
end
 
days = readOnly{'Sun', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat'}
print(days[1])
days[2] = 'Noday' --> stdin:1: attempt to update a read-only table

 

有時候,我們需要為 table 設定一個唯一的 key,那么可以使用這樣的技巧:

 

復制代碼 代碼如下:

local key = {} -- unique key
local t = {}
t[key] = value

 

 
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品99久久99久久久二8| 久99九色视频在线观看| 国产精品久久久久99| 日产精品久久久一区二区福利| 国产国语刺激对白av不卡| 亚洲男女性事视频| 亚洲国产精品va在线| 国产成人精品亚洲精品| 日韩欧美一区二区三区久久| 亚洲精品电影在线观看| 日韩国产激情在线| 国产精品久久久久久久天堂| 国产69精品99久久久久久宅男| 最新中文字幕亚洲| 性欧美长视频免费观看不卡| 久久免费少妇高潮久久精品99| 久久成人av网站| 91香蕉国产在线观看| 精品日韩美女的视频高清| 国产亚洲日本欧美韩国| 欧美激情一区二区三级高清视频| 欧美日韩一区二区在线| 亚洲成年人在线播放| 亚洲香蕉av在线一区二区三区| 国产一区二区三区在线播放免费观看| 亚洲精品欧美日韩专区| 日韩欧美亚洲一二三区| 欧美国产日产韩国视频| 日韩综合中文字幕| 亚洲精品国产精品国自产在线| 国产亚洲精品激情久久| 久久久久久亚洲精品不卡| 成人字幕网zmw| 国产欧美精品日韩| 亚洲欧美日韩中文视频| 国产91色在线|免| 91亚洲人电影| 96pao国产成视频永久免费| xxxx欧美18另类的高清| 2019中文字幕在线| 亚洲日韩欧美视频一区| 日韩精品视频在线免费观看| 日韩成人在线视频观看| 亚洲第一男人av| 91丝袜美腿美女视频网站| 日韩有码视频在线| 亚洲伦理中文字幕| 国产精品v日韩精品| 亚洲精品一区二区三区不| 欧美大片网站在线观看| 日韩成人在线免费观看| 亚洲精品成a人在线观看| 国产亚洲精品综合一区91| 国产亚洲精品久久久久久牛牛| 中文字幕不卡在线视频极品| 精品国产美女在线| 91在线播放国产| 中文字幕亚洲综合久久筱田步美| 中文在线资源观看视频网站免费不卡| 欧美一区深夜视频| 久久国产精品久久久久| 成人国产精品av| 亚洲精品中文字幕有码专区| 精品福利一区二区| 亚洲欧美中文在线视频| 亚洲一区二区中文| 成人在线国产精品| 国产欧美中文字幕| 4k岛国日韩精品**专区| 久久久黄色av| 精品国产拍在线观看| 91精品国产综合久久男男| 国产精品欧美日韩一区二区| 欧美黄色片免费观看| 最近2019年手机中文字幕| 久久成人在线视频| 九色精品免费永久在线| 亚洲激情在线观看| 欧美日本高清视频| 成人国产精品免费视频| 精品色蜜蜜精品视频在线观看| 亚洲国产成人精品久久| 亚洲高清久久久久久| 性欧美暴力猛交69hd| 欧美夫妻性生活视频| 日韩有码视频在线| 国产亚洲一区二区在线| 日韩在线视频免费观看| 国产精品久久久久久av福利软件| 日本欧美精品在线| 久久久亚洲影院| 色噜噜狠狠色综合网图区| 亚洲黄色有码视频| 国产亚洲综合久久| 欧美国产亚洲精品久久久8v| 亚洲欧美日韩一区二区三区在线| 91免费国产网站| 亚洲人a成www在线影院| 久热精品视频在线观看一区| 亚洲黄页视频免费观看| 91av在线看| 国产精品日本精品| 久久久久国产精品一区| 96pao国产成视频永久免费| 日韩在线视频网| 最近2019中文字幕大全第二页| 精品视频在线播放色网色视频| 国产精品视频免费在线| 亚洲天堂男人天堂女人天堂| 亚洲理论电影网| 国产精品一区二区三区久久| 欧美国产日韩免费| 亚洲综合视频1区| 日韩视频中文字幕| 久久久久免费视频| 亚洲国产成人精品女人久久久| xvideos成人免费中文版| 国内精品国产三级国产在线专| 精品无人区乱码1区2区3区在线| 色www亚洲国产张柏芝| 国产精品永久免费视频| 日韩日本欧美亚洲| 亚洲自拍偷拍一区| 在线观看免费高清视频97| 午夜精品一区二区三区在线播放| 伦理中文字幕亚洲| 亚洲伊人久久综合| 在线播放日韩av| 日韩小视频网址| 欧美日韩国产综合新一区| 成人激情视频在线| 亚洲人成电影网站| 亚洲成人a**站| 日韩在线播放av| 国产亚洲xxx| 日韩在线中文视频| 亚洲欧美成人在线| 亚洲性生活视频在线观看| 国模精品系列视频| 亚洲综合社区网| 欧美激情亚洲另类| 日本国产一区二区三区| 亚洲女人天堂网| 成人激情视频在线观看| 午夜精品理论片| 亚洲一区二区三区视频播放| 不卡av电影在线观看| 国产精品老牛影院在线观看| 久久精品亚洲精品| 91美女高潮出水| 久久久久久久久91| 亚洲成人1234| 午夜精品久久久久久久久久久久| 欧美成人免费全部观看天天性色| 欧美在线视频导航| 中文字幕日韩高清| 久久久精品日本| 欧美贵妇videos办公室| 国产在线观看精品| 日本久久91av| 国产一区二区三区免费视频| 日韩中文字幕国产| 日韩精品在线观| 高清视频欧美一级|