local a = {}
function a:test1(value)
print(value)
end
local b = {}
function b:test2(v1, v2)
v2(100);
end
b:test2(_, a.test1)
无法工作。值为nil。我可以通过在匿名函数中进行封装来找到解决方案。
b:test2(variable, function(value) a:test1(value) end)
但我认为它相当糟糕,好吧
正确的语法是什么?
local a = {}
function a:test1(value)
print(value)
end
local b = {}
function b:test2(v1, v2)
v2(100);
end
b:test2(_, a.test1)
无法工作。值为nil。我可以通过在匿名函数中进行封装来找到解决方案。
b:test2(variable, function(value) a:test1(value) end)
但我认为它相当糟糕,好吧
正确的语法是什么?
anotherObject:aFunction(variable, object.doStuff)
是正确的语法。
在函数中使用冒号 :
只是一个隐含了 self
参数作为第一个参数的调用或声明的语法糖。如果你想以更简洁的方式遵循你所展示的模式,你可以使用一个帮助函数。
local function bind(t, k)
return function(...) return t[k](t, ...) end
end
anotherObject:aFunction(variable, bind(object, 'doStuff'))
编辑:我相信解决您的问题需要在某个层面上进行绑定,而不是修改Lua解释器或使用代码转换步骤。这是因为Lua中的函数不携带有关其起源的任何信息。即,表格并不固有地拥有它们所存储的函数。
例如,以下是完全合法的Lua代码。
function Circle:area() -- function Circle.area(self)
-- ...
end
-- Evaluate the function in the "area" slot with Square as the self parameter.
Circle.area(Square)
local mt = {}
function mt:__index(k)
local v = self._slots[k]
if v == nil then
-- Ascend the inheritance tree.
-- This has to be done with rawget all the way up,
-- otherwise inherited functions would be repeatedly bound.
local p = self
repeat
p = rawget(p, '_parent')
if not p then break end
v = p._slots[k]
until v
end
if type(v) == 'function' then
-- Return a self-bound version of the function.
return function(...) return v(self, ...) end
end
return v
end
function mt:__newindex(k, v)
self._slots[k] = v
end
--- Demo & Tests ---
local function Object(parent)
local o = setmetatable({_slots = {}}, mt)
if parent then rawset(o, '_parent', parent) end
return o
end
local o1 = Object()
local o2 = Object(o1)
assert(o1.abc == nil, 'o1.abc should be nil')
o1.abc = 3
assert(o1.abc == 3, 'o1.abc should be 3')
assert(o2.abc == 3, 'o2.abc should be 3, inherited from o1')
o2.abc = 7
assert(o2.abc == 7, 'o2.abc should be 7, overriding o1')
assert(o1.abc == 3, 'o1.abc should be 3, unaffected by o2 setter')
function o1:test(bar)
return self.abc + bar
end
assert(type(o1.test) == 'function', 'o1.test should be a function')
assert(type(o2.test) == 'function', 'o2.test should be a function, inherited from o1')
assert(o1.test(5) == 8, 'o1.test(5) should return 3 + 5 = 8')
assert(o2.test(11) == 18, 'o2.test(11) should return 7 + 11 = 18')
function o2:test2(fn)
return self.abc + fn(7)
end
assert(o2.test2(o1.test) == 17, 'o2.test2(o1.test) should return 7 + (3 + 7) = 17')
o2.test3 = o1._slots.test -- proper function copying
assert(o2.test3(11) == 18, 'o2.test3(5) should return 7 + 11 = 18')
o2.abc = nil
assert(o2.abc == 3, 'o2.abc should be 3 again, inherited from o1 after clearing')
o2.abc = false
assert(o2.abc == false, 'o2.abc should be false, __index needs to differentiate between nil and false')
使用:
声明的对象方法需要将对象实例作为第一个参数。如果你使用:
调用它,它会自动添加,但是如果你只传递函数指针,你还需要传递this
。这意味着当你在某个对象中传递一个函数时,你也必须传递对象实例。以下是有效的:
local a = {}
function a:test1(value)
print(value)
end
local b = {}
function b:test2(obj, v2)
v2(obj, 100); -- object instance is always the first param of a ":"-style func
end
b:test2(a, a.test1) -- passing object instance and a function
bind()
解决方案的基础上,我发现在一个模块中,这个解决方案稍微更加简洁:local m = {}
m.__index = m
m.word = 'bar'
function m:bind(fn)
return function(...) return self[fn](self, ...) end
end
function m:foo(fn)
print("Foo " .. self.word)
end
function m:start()
hs.timer.new(42, self:bind('foo'))
end
你的代码将会起作用。原因如Ryan所说。 我怀疑在函数anotherObject:aFunction()中,你使用了错误的方式来调用object.stuff。正确的方式是这样的:
local a = {}
function a:test1()
print(1)
end
local b = {}
function b:test2(v1, v2)
v2();
end
b:test2(_, a.test1)