【发布时间】:2011-08-28 05:36:50
【问题描述】:
作为练习,我正在尝试在 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 表成员的插入函数正在显示。这不仅比原来的Set.insert(s, v) 问题更丑陋,而且还容易出现一些严重的问题(比如如果“插入”是某人试图输入的有效密钥会发生什么?)。又到了翻书的时候了。如果我尝试这样做会发生什么?:
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元表的"__call"键返回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]: ?
在这一点上,我被难住了。我完全不知道从这里去哪里。我花了一个小时在这个代码上进行了不同程度的越来越绝望的变化,但最终结果是我没有任何工作。在这一点上,我忽略了什么无疑是显而易见的事情?
【问题讨论】:
-
只想说我非常喜欢你的用户名