Lua Metatable


Dalam jadual Lua kita boleh mengakses kekunci yang sepadan untuk mendapatkan nilai, tetapi kita tidak boleh beroperasi pada dua jadual.

Oleh itu, Lua menyediakan metatable (Metatable), yang membolehkan kami mengubah tingkah laku jadual Setiap tingkah laku dikaitkan dengan metamethod yang sepadan.

Sebagai contoh, menggunakan metatable kita boleh mentakrifkan cara Lua mengira operasi tambah a+b dua jadual.

Apabila Lua cuba menambah dua jadual, ia mula-mula menyemak sama ada salah satu daripada dua jadual itu mempunyai jadual meta, dan kemudian menyemak sama ada terdapat medan yang dipanggil "__tambah jika ditemui, nilai yang sepadan dipanggil". Untuk medan masa nyata seperti "__add", nilai sepadannya (selalunya fungsi atau jadual) ialah "meta-method".

Terdapat dua fungsi yang sangat penting untuk mengendalikan metatable:

  • setmetatable(table, metatable): Set metatable untuk jadual yang ditentukan ( metatable) , jika nilai kunci __metatable wujud dalam metatable (metatable), setmetatable akan gagal.

  • getmetatable(table): Mengembalikan jadual meta objek.

Contoh berikut menunjukkan cara menetapkan metatable untuk jadual tertentu:

mytable = {}                          -- 普通表 
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表

Kod di atas juga boleh ditulis terus dalam satu baris:

rreee

Yang berikut dikembalikan Metatable Objek:

mytable = setmetatable({},{})

__metamethod indeks

Ini ialah kunci metatable yang paling biasa digunakan.

Apabila anda mengakses jadual mengikut kunci, jika kunci itu tidak mempunyai nilai, Lua akan mencari kunci __index dalam jadual meta jadual (dengan andaian terdapat jadual meta). Jika __index mengandungi jadual, Lua mencari kunci yang sepadan dalam jadual.


Kita boleh menggunakan arahan lua untuk memasuki mod interaktif untuk melihat:

getmetatable(mytable)                 -- 这回返回mymetatable

Jika __index mengandungi fungsi, Lua akan memanggil fungsi itu, dan jadual serta kunci akan menjadi sebagai Parameter dihantar ke fungsi.

Metamethod __index menyemak sama ada elemen itu wujud dalam jadual Jika ia tidak wujud, hasil pulangan adalah tiada, hasilnya dikembalikan oleh __index.

$ lua
Lua 5.3.0  Copyright (C) 1994-2015 Lua.org, PUC-Rio
> other = { foo = 3 } 
> t = setmetatable({}, { __index = other }) 
> t.foo
3
> t.bar
nil

Hasil keluaran contoh ialah:

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

print(mytable.key1,mytable.key2)

Analisis contoh:

  • tugasan jadual mytable ialah{key1 = "value1"}.

  • mytable menetapkan metatable dan metamethodnya ialah __index.

  • Cari kunci1 dalam jadual mytable Jika ditemui, kembalikan elemen tersebut Jika tidak ditemui, teruskan.

  • Cari key2 dalam jadual mytable Jika dijumpai, kembalikan metatablevalue Jika tidak dijumpai, teruskan.

  • Tentukan sama ada metatable mempunyai kaedah __index Jika kaedah __index ialah fungsi, panggil fungsi tersebut.

  • Dalam kaedah meta, semak sama ada parameter kunci "key2" dihantar masuk (mytable.key2 telah ditetapkan Jika parameter "key2" dihantar, "metatablevalue"). dikembalikan, jika tidak, nilai mytable yang sepadan dikembalikan.


Kita hanya boleh menulis kod di atas sebagai:

value1	metatablevalue

Ringkasan

Apabila Lua mencari jadual elemen Peraturan sebenarnya ialah 3 langkah berikut:

  • 1. Jika dijumpai, kembalikan elemen tersebut

  • 2. Tentukan sama ada jadual mempunyai metatable.

  • 3. Tentukan sama ada metatable mempunyai kaedah __index Jika kaedah __index adalah nil, kembalikan nil jika kaedah __index ialah jadual, ulangi 1, 2, dan 3; kaedah __index ialah fungsi, nilai pulangan fungsi dikembalikan.


__newindex meta-method

__newindex meta-method digunakan untuk mengemas kini jadual, dan __index digunakan untuk mengakses jadual.

Apabila anda menetapkan nilai kepada indeks jadual yang hilang, penterjemah mencari metamethod __newindex: jika wujud, ia memanggil fungsi ini tanpa melaksanakan tugasan.

Contoh berikut menunjukkan aplikasi __newindex meta-method:

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

Output pelaksanaan contoh di atas ialah:

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

print(mytable.key1)

mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)

Dalam contoh di atas, meta- kaedah __newindex ditetapkan dalam jadual Apabila menetapkan nilai kepada kunci indeks baharu (kekunci baru) (mytable.newkey = "nilai baharu 2"), metamethod akan dipanggil tanpa memberikan nilai. Jika kunci indeks sedia ada (key1) diberikan, nilai akan diberikan tanpa memanggil meta-method __newindex.

Contoh berikut menggunakan fungsi rawset untuk mengemas kini jadual:

value1
nil	新值2
新值1	nil

Output pelaksanaan contoh di atas ialah:

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)

Tambah operator pada jadual

Contoh berikut menunjukkan operasi penambahan dua jadual:

new value	"4"

Hasil keluaran pelaksanaan contoh di atas ialah:

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end

-- 两表相加操作
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

Kunci __add disertakan dalam metatable dan operasi tambah dilakukan. Senarai operasi yang sepadan dalam jadual adalah seperti berikut:

模式描述
__add对应的运算符 '+'.
__sub对应的运算符 '-'.
__mul对应的运算符 '*'.
__div对应的运算符 '/'.
__mod对应的运算符 '%'.
__unm对应的运算符 '-'.
__concat对应的运算符 '..'.
__eq对应的运算符 '=='.
__lt对应的运算符 '<'.
__le对应的运算符 '<='.

__metakaedah panggilan

__metakaedah panggilan dipanggil apabila Lua memanggil nilai. Contoh berikut menunjukkan pengiraan jumlah elemen dalam jadual:

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

Output pelaksanaan contoh di atas ialah:

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)
    local mn = 0
    for k, v in pairs(t) do
        if mn < k then
            mn = k
        end
    end
    return mn
end

-- 定义元方法__call
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))

__tostring metamethod

__tostring metamethod digunakan untuk mengubah suai tingkah laku output jadual. Dalam contoh berikut, kami telah menyesuaikan kandungan output jadual:

70

Hasil output pelaksanaan contoh di atas ialah:

mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
		sum = sum + v
	end
    return "表所有元素的和为 " .. sum
  end
})
print(mytable)

Daripada artikel ini, kita boleh tahu bahawa metatable boleh memudahkan fungsi kod kami Oleh itu, memahami metatable Lua membolehkan kami menulis kod Lua yang lebih ringkas dan lebih baik.