В качестве упражнения я пытаюсь сделать реализацию множества в Lua.В частности, я хочу взять упрощенную реализацию набора Pil2 11.5 и расширить ее, чтобы включить возможность вставлять значения, удалять значения и т. Д.
Теперь очевидный способ сделать это (и способ, которым это работает) -это:
Set = {}
function Set.new(l)
local s = {}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.insert(s, v)
s[v] = true
end
ts = Set.new {1,2,3,4,5}
Set.insert(ts, 5)
Set.insert(ts, 6)
for k in pairs(ts) do
print(k)
end
Как и ожидалось, я распечатал числа от 1 до 6.Но эти звонки на Set.insert(s, value)
действительно довольно уродливы.Я бы предпочел назвать что-то вроде ts:insert(value)
.
Моя первая попытка решения этой проблемы выглядела так:
Set = {}
function Set.new(l)
local s = {
insert = function(t, v)
t[v] = true
end
}
for _, v in ipairs(l) do
s[v] = true
end
return s
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
Это работает в основном нормально, пока вы не увидите, чтоиз этого вытекает:
1
2
3
4
5
6
insert
Совершенно очевидно, что отображается функция вставки, которая является членом заданной таблицы.Это не только еще страшнее, чем исходная проблема Set.insert(s, v)
, но и подвержено серьезным проблемам (например, что произойдет, если «insert» - это действительный ключ, который кто-то пытается ввести?).Пришло время снова попасть в книги.Что произойдет, если я попробую это вместо этого ?:
Set = {}
function Set.new(l)
local s = {}
setmetatable(s, {__call = Set.call})
for _, v in ipairs(l) do
s[v] = true
end
return s
end
function Set.call(f)
return Set[f]
end
function Set.insert(t, v)
t[v] = true
end
ts = Set.new {1,2,3,4,5}
ts:insert(5)
ts:insert(6)
for k in pairs(ts) do
print(k)
end
Теперь я читаю этот код так:
- Когда я звоню
ts:insert(5)
, факт, что insert
не существует для вызова означает, что для метатаблицы ts
будет выполняться поиск "__call"
. - Ключ
ts
метатаблицы *1029* возвращает Set.call
. - Теперь
Set.call
вызывается с именем insert
, что заставляет его возвращать функцию Set.insert
. Set.insert(ts, 5)
вызывается.
Что действительно происходит, так это:
lua: xasm.lua:26: attempt to call method 'insert' (a nil value)
stack traceback:
xasm.lua:26: in main chunk
[C]: ?
И в этот момент я в тупике.Я понятия не имею, куда идти отсюда.Я взломал целый час с различными степенями все более отчаянных изменений в этом коде, но в результате у меня ничего не работает.Что, несомненно, очевидно, я упускаю из виду в этот момент?