メタテーブルは、以前のより強力なテーブルにすることができます。データに接続され、メタメソッドという名前の値が含まれています。メタメソッドは、指定されたアクションに対応するデータに発動されます。
次のコードを考慮してください:
local list = {1, 2}print(list[3])
このコードは、リストのリストで第 3 インデックスのためにリストを検索し、何も見つかり、nil を返します。これは正解ではありません。代わりに、コードはリストを検索し、第 3 インデックスを見つけ、その後、メタテーブルが付加された表に返します、nil が付加されていない場合は、返します。
メタテーブルを操作する
テーブルのメタテーブルを追加および見つけるための 2つの主要な機能は、setmetatable およびgetmetatableです
local x = {}local metaTable = {} -- メタテーブルはテーブルです!setmetatable(x, metaTable) -- メタテーブルと呼ばれる x を与えます!print(getmetatable(x)) --> table: [hexadecimal memory address]
setmetatable 機能は、メタテーブルの設定中のテーブルを返しますので、これらの 2つのスクリプトは同じことを行います:
local x = {}setmetatable(x, {})
local x = setmetatable({}, {})
メタメソッド
メタメソッドは、メタテーブル内に保存される関数です。テーブルを呼び出したり、テーブルを追加したり、テーブルを分割することもできます。ここにメタメソッドのリストがあります:
メソッド | 説明 |
---|---|
__index(テーブル、インデックス) | table[index]がインデックスされるときに発動されます。table[index]が n である場合は、その表がインデックスされます。 |
__newindex(表、インデックス、値) | table[index]が設定されるときに発生する。(table[index] = 値) が n の場合、そのテーブルがインデックスされます。 |
__call(table、... ) | テーブルが関数として呼び出されるとき、... はパスされた引数です。 |
__concat(表、値) | テーブルに.. 接頭子オペレーターを使用すると、ファイアが発生します。 |
__unm(テーブル) | テーブルに unary オペレーターを使用したときに発動します。 |
__add(テーブル、値) | + オペレーター。 |
__sub(テーブル、値) | – 控除オペレーター。 |
__mul(テーブル、値) | * 複製オペレーター。 |
__div(テーブル、値) | / 分割オペレーター。 |
__idiv(テーブル、値) | //フロア分割オペレータ。 |
__mod(テーブル、値) | % modulus オペレーター。 |
__pow(テーブル、値) | ^ 凡数化オペレーター。 |
__tostring(テーブル) | テーブルに tostring が呼び出されるときにファイアーされます。 |
__metable | 現在、メタテーブルをロックして、メタテーブルとセットメタテーブルがメタテーブルではなく、メタテーブルとセットメタテーブルがメタテーブルであることがメタテーブルとセットメタテーブルの間でエラーになる可能性があります。非機能値。 |
__eq(テーブル、値) | 操作子 == を操作子として使用する |
__lt(テーブル、値) | オペレーター ¹ 未満 |
__le(テーブル、値) | Theoperator¹ |
__モード | 弱いテーブルに使用され、テーブルのキーと/または値が弱いかどうかを宣言します。 注: 参照する Roblox インスタンスは決して弱いではありません。これらの参照を持つテーブルは、ガビジョンを収集しないです。 |
__gc(テーブル) | テーブルがガビジンを回収するときに発動します。 注: Roblox では、このメタメソッドは無効になっています。 |
__len(テーブル) | オブジェクトに # 長さオペレーターを使用したときに発動します。 |
__iter(テーブル) | 一般化されたイテレータを使用しているときにカスタムイテレータを表す。 |
関数を作成するときに、 arithmetic または relational メタメソッドの両方の機能の場合、メタメソッドの 2つの機能パラメータ は、メタメソッドを実行したテーブルと他の値の間で相互に交換可能です。たとえば、スケーラーの分割でベクトルオペレーションを行う場合、場合によっては、両方のシナリオに注意
local vector2 = {__type = "vector2"}
local mt = {__index = vector2}
function mt.__div(a, b)
if type(a) == "number" then
-- a はスケーラーです、b はベクトルです
local scalar, vector = a, b
return vector2.new(scalar / vector.x, scalar / vector.y)
elseif type(b) == "number" then
-- a はベクトルであり、b はスケーラーです
local vector, scalar = a, b
return vector2.new(vector.x / scalar, vector.y / scalar)
elseif (a.__type and a.__type == "vector2" and b.__type and b.__type == "vector2") then
-- 両方 a と b はベクトルです
return vector2.new(a.x / b.x, a.y / b.y)
end
end
function mt.__tostring(t)
return t.x .. ", " .. t.y
end
function vector2.new(x, y)
local self = setmetatable({}, mt)
self.x = x or 0
self.y = y or 0
return self
end
local a = vector2.new(10, 5)
local b = vector2.new(-3, 4)
print(a / b) -- -3.333333333333、1.25
print(b / a) -- 0.3、0.8
print(2 / a) -- 0.2、0.4
print(a / 2) -- 5, 2.5
メタテーブルを使用する
メタテーブルを使用する方法はたくさんあります。たとえば、__unm メタメソッド (を使用してテーブルをネガティブにする):
local metatable = {
__unm = function(t) -- __unm はユニー - オペレーター
local negated = {}
for key, value in t do
negated[key] = -value -- このテーブルのすべての値をネガティブにする
end
return negated -- テーブルを返す
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
print(table.concat(-table1, "; ")) --> -10; -11; -12
Here's an interesting way to declare things using __index :
local metatable = {__index = {x = 1}}local t = setmetatable({}, metatable)print(t.x) --> 1
__index は、x がテーブルにインデックスされ、見つからなかったときに発動しました。Lua は、__index テーブルで x のインデックスを見つけ、その 1 つを返しました。
今では、単純な関数でそれを簡単に行うことができますが、それはどこから来たのかがたくさんあります。これを例に挙げてください:
local t = {10, 20, 30}print(t(5))
さて、明らかにテーブルは呼び出すことができません。それはクレイジーですが、メタテーブルではできます。(驚き、驚き!)
local metatable = {
__call = function(t, param)
local sum = {}
for i, value in ipairs(t) do
sum[i] = value + param -- 引数 (5) を値に追加し、新しい テーブル (t) に配置します。
end
return unpack(sum) -- 個々のテーブルの値を返す
end
}
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35
テーブルを追加するなど、さらにできます!
local table1 = {10, 11, 12}local table2 = {13, 14, 15}for k, v in table1 + table2 doprint(k, v)end
これは、テーブル上の arithmetic を実行しようとしているというメッセージでエラーが発生します。メタテーブルを使用して、これを metatable で試してみましょう。
local metatable = {
__add = function(t1, t2)
local sum = {}
for key, value in t1 do
sum[key] = value
end
for key, value in t2 do
if sum[key] then
sum[key] += value
else
sum[key] = value
end
end
return sum
end
}
local table1 = setmetatable({10, 11, 12}, metatable)
local table2 = setmetatable({13, 14, 15}, metatable)
for k, v in table1 + table2 do
print(k, v)
end
ケースを使用する
さあ、これらの例はすべて単純な関数として実装できますが、それ以上ができます。これは、可能にラギーな数学問題が入力されたときに数を記憶化するシンプルなプログラムを試してみましょう。
この場合、__index メタメソッドを使用して、単純にするために使用します:
local function mathProblem(num)
for i = 1, 20 do
num = math.floor(num * 10 + 65)
end
for i = 1, 10 do
num += i - 1
end
return num
end
local metatable = {
__index = function(object, key)
local num = mathProblem(key)
object[key] = num
return num
end
}
local t = setmetatable({}, metatable)
print(t[1]) -- これは数字を使用するのが初めてなので、数学関数を実行しなければなりません。
print(t[2]) -- この番号を使用するのは初めてのため、遅くなります。
print(t[1]) -- will be fast because it's just grabbing the number from the table.
Rawset、Rawget、Rawequal
メタテーブルをプレイすると、いくつかの問題が発生する可能性があります。メタテーブルを作成するために __index メタメソッドを使用する必要がある場合、メタテーブルのメタメソッドには __newindex メタメソッド
local t = setmetatable({}, {
__index = function(self, i)
self[i] = i * 10 -- たとえばの例
return self[i]
end,
__newindex = function(self, i, v)
--何もしないでください、因みに私たちは、あなたが値をテーブルに正常な方法で設定することを望まない
end
})
print(t[1]) -- Causes a C-Stack overflow
今、なぜそれがスタックオーバーフローを引き起こすのですか?スタックオーバーフローは、__index 関数からself[i] 以上呼び出そうとしたときに発生しますが、それを引き起こす原因は何ですか?在<
問題は、__newindex は値を設定できません。その存在は、Standard t[i] = v メソッドでテーブルに追加される値を停止します。これをパスするには、rawset 機能を使用します。
local t = setmetatable({}, {
__index = function(self, i)
rawset(self, i, i * 10)
return self[i]
end,
__newindex = function(self, i, v)
--何もしないでください、因みに私たちは、あなたが値をテーブルに正常な方法で設定することを望まない
end
})
print(t[1]) -- prints 10
セットデータタイプを使用中
コレクション は、オーダーがない 、重複要素がない コレクションのアイテムのコレクションです。アイテムは、オーダーがありません または、2> 重複要素がありません2> コレクション内に含まれていません。メタテーブルを使用して、Lua スクリプト内のコレクションを構築および
基本メソッド
次のコードには、基本的なセット機能が含まれており、新しいセットを作成し、アイテムを追加し、削除し、セット内のアイテムをチェックし、セッ設定するの内容を出力します。
local Set = {}
Set.__index = Set
-- オプションのアイテムリストからセットを構築する機能
function Set.new(items)
local newSet = {}
for key, value in items or {} do
newSet[value] = true
end
return setmetatable(newSet, Set)
end
-- セットにアイテムを追加する機能
function Set:add(item)
self[item] = true
end
-- セットからアイテムを削除する機能
function Set:remove(item)
self[item] = nil
end
-- セットにアイテムが含まれているかどうかをチェックする機能
function Set:contains(item)
return self[item] == true
end
-- デバッグ用にコマを使用してリストを出力する関数
function Set:output()
local elems = {}
for key, value in self do
table.insert(elems, tostring(key))
end
print(table.concat(elems, ", "))
end
セットを作成
新しいセットを構成するには、Set.new() を呼び出し、オプションのアイテム配列を追加してください。
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
注:定義により、セットにはオーダーのコンセプトがありません。
アイテムを追加
既存のセットにアイテムを追加するには、Set:add() メソッドを使用してください。
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})fruits:add("Mango")
アイテムを削除
コレクションからアイテムを削除するには、Set:remove() コマンドを呼び出し、アイテム名を入力します。
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})fruits:remove("Orange")
アイテムをチェック
Set:contains() を使用して、セット内の特定のアイテムを確認します。
local fruits = Set.new({"Apple", "Lemon", "Orange", "Cherry", "Lime", "Peach"})local result1 = fruits:contains("Cherry")print(result1) -- はいlocal result2 = fruits:contains("Watermelon")print(result2) -- false
追加のメソッド
セットには、他の便利なオペレーションが実装されており、アイテムをセット間で比較したり、セットを組み合わせたり、1つのセットを別のセットから削除できます。
交差点
セットを Venn 図として検討すると、2つのセットの 交差点 を次のように取得できます。これは、両方のセットに表示されるアイテムを意味します。
local function getIntersection(set1, set2)
local result = Set.new()
for key, value in set1 do
if set2:contains(key) then
result:add(key)
end
end
return result
end
local freshFruits = Set.new({"Mango", "Lemon", "Orange", "Cherry", "Lime", "Peach"})
local frozenFruits = Set.new({"Mango", "Peach", "Pineapple"})
local commonFruits = getIntersection(freshFruits, frozenFruits)
commonFruits:output() -- Mango, Peach
ユニオン
ユニオンを取得するには、次の関数を使用して 2つのセットのユニオンを取得できます。これは、コレクションのアイテムを両方のセットに含めることを意味します。この関数は、メタテーブルの__addメソッドを使用して、set1 + set2の追加のショートカットを提供します。
function Set:__add(otherSet)
local result = Set.new()
for entry in self do
result[entry] = true
end
for entry in otherSet do
result[entry] = true
end
return result
end
local sweetFruits = Set.new({"Apple", "Mango", "Cherry", "Peach"})
local sourFruits = Set.new({"Lemon", "Lime"})
local allFruits = sweetFruits + sourFruits
allFruits:output() -- ピーチ、ライム、アップル、チェリー、レモン、マンゴ
控除
以下の関数を使用して、別のセットのアイテムからすべてのアイテムを削除できます。これは、上記の関数と同様のメタテーブル __sub メソッドを使用して、set1 - set2 のサブトラクションショートカットを提供します。
function Set:__sub(otherSet)
local result = Set.new()
for entry in self do
result[entry] = true
end
for entry in otherSet do
result[entry] = nil
end
return result
end
local allFruits = Set.new({"Apple", "Lemon", "Mango", "Cherry", "Lime", "Peach"})
local sourFruits = Set.new({"Lemon", "Lime"})
local sweetFruits = allFruits - sourFruits
sweetFruits:output() -- Mango, Apple, Cherry, Peach