メタテーブルは、テーブルが以前よりも強力になるようにする。データに付属し、メタメソッドと呼ばれる値を含んでいます。メタメソッドは、付属するデータに特定のアクションが使用されたときに発射されます。
メタテーブルを操作
テーブルのメタテーブルを追加して見つけるための 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] がインデックス化されると発火し、table[index] が nil である場合、そのテーブルがインデックス化されます。また、テーブルに設定することもでき、その場合、そのテーブルがインデックス化されます。 |
__newindex(table, index, value) | が設定されようとしているときに発火し、 が である場合また、テーブルに設定でき、その場合そのテーブルはインデックス化されます。 |
__call(table, ...) | テーブルが機能として呼ばれるときに発火します、 ... はパスされた引数です。 |
__concat(table, value) | テーブルに .. 結合演算子が使用されたときに発火します。 |
__unm(table) | テーブルで単一の – オペレータが使用されるときに発火します。 |
__add(table, value) | + 追加演算子。 |
__sub(table, value) | – 減算オペレータ。 |
__mul(table, value) | * 乗算オペレータ。 |
__div(table, value) | The / 分離演算子。 |
__idiv(table, value) | // フロア分割オペレータ。 |
__mod(table, value) | % モジュールオペレーター。 |
__pow(table, value) | ^ 経験乗数オペレータ。 |
__tostring(table) | table で tostring が呼び出されたときに発射されます。 |
__metatable | 存在する場合、メタテーブルをロックして、getmetatable() がメタテーブルではなくこれを返し、setmetatable() がエラーになります。非機能値。 |
__eq(table, value) | オペレータ¹と同じである == |
__lt(table, value) | < 少なくなる演算子¹ |
__le(table, value) | The <= 演算子¹ |
__mode | 弱いテーブルで使用し、テーブルのキーと/または値が弱いかどうかを宣言します。Roblox インスタンスへの参照は決して弱くないことに注意してください。このような参照を保持するテーブルは、決してゴミ集めされません。 |
__len(table) | オブジェクトに # 長さオペレーターが使用されたときに発射されます。 |
__iter(table) | 一般化されたイテレーションを使用するときに、カスタムイテレータを示すために使用されます。 |
算術または関係メタメソッドの機能を書くときは、メタメソッドを発射したテーブルと他の値の間で、2つの機能パラメータが交換可能であることに注意してください。たとえば、スカラー分割でベクトル操作を行うときは、 commutative ではありません。たとえば、自分の vector2 クラスのメタメソッドを書いていた場合、どちらのシナリオをカバーするか注意したいでしょう。
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.3333333333333, 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
ここに、__index を使用して物事を宣言する興味深い方法があります:
local metatable = {__index = {x = 1}}local t = setmetatable({}, metatable)print(t.x) --> 1
__index は、x がテーブルにインデックス化されて見つからなかったときに発射されました。Luau は次に、__index テーブルを検索し、x と呼ばれるインデックスを見つけ、それを返しました。
今や簡単にそれをシンプルな関数で行うことができますが、それがどこから来たかというと、もっと多くのものがあります。例を挙げてみましょう:
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
これは、テーブルで算術を実行しようとしているというエラーが発生しますが、メタテーブルを使用すると機能します:
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 メタメソッドを使用する必要がありますが、そのテーブルのメタテーブルにも __newindex メタメソッドがある場合、メタメソッドを呼び出さずに Luau 内蔵機能 rawset() を使用して値を設定したいでしょう。これらの機能を使用しない場合、次のコードを使用した例として参考にしてください。
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 stack overflow
スタックオーバーフローは、機能を自身から何度も呼び出そうとすると発生します。上記の __index 関数では、self[i] が値に設定されているので、次の行に到達すると、self[i] が存在し、おそらく __index メタメソッドを呼び出さないでしょう。問題は、__newindex に値を設定できないことです。その存在は、標準の 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]) --> 10
セットデータ型を使用する
A セット は、順序も重複要素もないアイテムのコレクションです。アイテムが は または は セッ設定する内に含まれていない。メタテーブルを使用すると、Luau スクリプト内でセットを作成して操作できます。
基本的な手法
次のコードには、基本セット機能が含まれており、新しいセットを作成したり、アイテムを追加したり、セットにアイテムが含まれているかどうかをチェックしたり、セッ設定するの内容を出力したりできます。
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つのセットから他のセットを控除することができます。
交差点
セットをヴェンンダイアグラムとして考えると、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() -- ピーチ、ライム、アップル、チェリー、レモン、マンゴ
減算
次の機能を介して、1つのセットから別のセットのアイテムすべてを削除できます。上の機能と同様、これは metatable __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