В Lua две таблицы, созданные отдельно, считаются «разными». Но если вы создадите таблицу один раз, вы можете назначить ее любым переменным, которые захотите, и когда вы сравните их, Lua скажет вам, что они равны. Другими словами:
t = {}
key = { a = "a" }
t[key] = 4
key2 = key
...
t[key2] -- returns 4
Итак, это простой, чистый способ делать то, что вы хотите. Храните key
где-нибудь, чтобы вы могли получить обратно 4
, используя его. Это тоже очень быстро.
Если вы действительно не хотите этого делать ... ну, есть способ. Но это неэффективно и некрасиво.
Первая часть - создание функции, которая сравнивает две отдельные таблицы. Он должен возвращать true, если две таблицы «эквивалентны», и false, если они не являются. Давайте назовем это эквивалентным. Это должно работать так:
equivalent({a=1},{a=1}) -- true
equivalent({a=1,b=2}, {a=1}) -- false
equivalent({a={b=1}}, {a={b=2}}) -- false
Функция должна быть рекурсивной, чтобы обрабатывать таблицы, которые содержат сами таблицы. Это также не должно быть одурачено, если одна из таблиц «содержит» другую, но имеет больше элементов. Я вышел с этой реализацией; возможно, есть и лучшие.
local function equivalent(a,b)
if type(a) ~= 'table' then return a == b end
local counta, countb = 0, 0
for k,va in pairs(a) do
if not equivalent(va, b[k]) then return false end
counta = counta + 1
end
for _,_ in pairs(b) do countb = countb + 1 end
return counta == countb
end
Я не собираюсь объяснять эту функцию здесь. Надеюсь, достаточно ясно, что он делает.
Другая часть головоломки состоит в том, чтобы заставить t
использовать функцию equivalent
при сравнении клавиш. Это можно сделать с помощью аккуратных метатабируемых манипуляций и дополнительной таблицы «хранения».
Мы в основном превращаем t
в самозванца. Когда наш код говорит ему сохранить значение под ключом, он не сохраняет его сам по себе; вместо этого он дает его дополнительной таблице (назовем это store
). Когда код запрашивает t
значение, он ищет его в store
, но используя функцию equivalent
, чтобы получить его.
Это код:
local function equivalent(a,b)
... -- same code as before
end
local store = {} -- this is the table that stores the values
t = setmetatable({}, {
__newindex = store,
__index = function(tbl, key)
for k,v in pairs(store) do
if equivalent(k,key) then return v end
end
end
})
Пример использования:
t[{a = 1}] = 4
print(t[{a = 1}]) -- 4
print(t[{a = 1, b = 2}]) -- nil