从函数返回的 table 继承
Inherit from table returned from function
有一个 API 提供的函数,我们称它为 createBase
其中 returns 一个 table (对象)。我想给这个 table 添加方法,但我不能只做 x = createBase()
然后 function x:foo()
因为我有另一个类似于 createBase
的函数,但它是 createExtended
.用我目前的代码可能更容易解释:
import api --I don't know how you'd do this in vanilla Lua, I'd use os.loadAPI("api") but that's computercraft specific, I think
Extended = {}
function Extended:foo()
print("foo from extended")
end
function createExtended(params)
x = api.createBase(params)
Extended.__index = x
return Extended --this is obviously wrong: you can't return a class and expect it to be an object
end
当然,这行不通:但我也不知道如何让它工作。假设 createBase
返回的 table 有一个名为 bar
的函数,它只打印 bar from base
。使用此测试代码,给出以下输出:
e = createExtended()
e.foo() --prints "foo from extended"
e.bar() --nil, therefor error
除了在 createExtended
中定义 function x.bar()
之外,我怎样才能做到这一点?
提前致谢。
最简单的方法是直接将方法附加到它,而不是使用元table。
local function extend(super_instance)
super_instance.newMethod = newMethod
return super_instance
end
local function createExtended(...)
return extend(createSuper(...))
end
这会起作用,除非你的 superclass 使用 __newindex
(例如,防止你写入未知的 properties/methods),或者使用 [=14= 迭代键] 或 next
,因为它现在将有一个额外的密钥。
如果由于某种原因您无法修改该对象,您将不得不 'wrap' 修改它。
您可以创建一个新实例,其中 "proxies" 它的所有方法、属性和运算符到另一个实例,除了它添加额外的字段和方法。
local function extend(super_instance)
local extended_instance = {newMethod = newMethod}
-- and also `__add`, `__mul`, etc as needed
return setmetatable(extended_instance, {__index = super_instance, __newindex = super_instance})
end
local function createExtended(...)
return extend(createSuper(...))
end
这将适用于简单的 classes,但不适用于所有用途:
Table 像 pairs
和 next
这样的迭代不会找到原始 table 中的键,因为它们实际上并不存在。如果 superclass 检查给定对象的 metatable (或者如果 superclass 实际上是一个用户数据),它也不会工作,因为你会发现改为扩展元table。
然而,许多纯 Lua classes 不会做这些事情,所以这仍然是一个相当简单的方法,可能对你有用。
你也可以做类似围棋的事情;无需使用 'extend' a class 的方法,您只需将 class 作为一个字段嵌入,并为直接调用仅调用方法的包装 class 上的方法提供便利在 'extended' class.
由于 'methods' 在 Lua 中的工作方式,这有点复杂。您无法判断 属性 是一个函数即 属性 还是它实际上是一个方法。下面的代码假定所有带有 type(v) == "function"
的属性实际上都是方法,这通常是正确的,但实际上可能不适用于您的特定情况。
在最坏的情况下,您可以手动维护您想要 'proxy' 的 methods/properties 列表,但这取决于您需要代理多少个 class 以及有多少个他们拥有的属性可能会变得笨拙。
local function extend(super_instance)
return setmetatable({
newMethod = newMethod, -- also could be provided via a more complicated __index
}, {
__index = function(self, k)
-- Proxy everything but `newMethod` to `super_instance`.
local super_field = super_instance[k]
if type(super_field) == "function" then
-- Assume the access is for getting a method, since it's a function.
return function(self2, ...)
assert(self == self2) -- assume it's being called like a method
return super_field(super_instance, ...)
end
end
return super_field
end,
-- similar __newindex and __add, etc. if necessary
})
end
local function createExtended(...)
return extend(createSuper(...))
end
有一个 API 提供的函数,我们称它为 createBase
其中 returns 一个 table (对象)。我想给这个 table 添加方法,但我不能只做 x = createBase()
然后 function x:foo()
因为我有另一个类似于 createBase
的函数,但它是 createExtended
.用我目前的代码可能更容易解释:
import api --I don't know how you'd do this in vanilla Lua, I'd use os.loadAPI("api") but that's computercraft specific, I think
Extended = {}
function Extended:foo()
print("foo from extended")
end
function createExtended(params)
x = api.createBase(params)
Extended.__index = x
return Extended --this is obviously wrong: you can't return a class and expect it to be an object
end
当然,这行不通:但我也不知道如何让它工作。假设 createBase
返回的 table 有一个名为 bar
的函数,它只打印 bar from base
。使用此测试代码,给出以下输出:
e = createExtended()
e.foo() --prints "foo from extended"
e.bar() --nil, therefor error
除了在 createExtended
中定义 function x.bar()
之外,我怎样才能做到这一点?
提前致谢。
最简单的方法是直接将方法附加到它,而不是使用元table。
local function extend(super_instance)
super_instance.newMethod = newMethod
return super_instance
end
local function createExtended(...)
return extend(createSuper(...))
end
这会起作用,除非你的 superclass 使用 __newindex
(例如,防止你写入未知的 properties/methods),或者使用 [=14= 迭代键] 或 next
,因为它现在将有一个额外的密钥。
如果由于某种原因您无法修改该对象,您将不得不 'wrap' 修改它。
您可以创建一个新实例,其中 "proxies" 它的所有方法、属性和运算符到另一个实例,除了它添加额外的字段和方法。
local function extend(super_instance)
local extended_instance = {newMethod = newMethod}
-- and also `__add`, `__mul`, etc as needed
return setmetatable(extended_instance, {__index = super_instance, __newindex = super_instance})
end
local function createExtended(...)
return extend(createSuper(...))
end
这将适用于简单的 classes,但不适用于所有用途:
Table 像 pairs
和 next
这样的迭代不会找到原始 table 中的键,因为它们实际上并不存在。如果 superclass 检查给定对象的 metatable (或者如果 superclass 实际上是一个用户数据),它也不会工作,因为你会发现改为扩展元table。
然而,许多纯 Lua classes 不会做这些事情,所以这仍然是一个相当简单的方法,可能对你有用。
你也可以做类似围棋的事情;无需使用 'extend' a class 的方法,您只需将 class 作为一个字段嵌入,并为直接调用仅调用方法的包装 class 上的方法提供便利在 'extended' class.
由于 'methods' 在 Lua 中的工作方式,这有点复杂。您无法判断 属性 是一个函数即 属性 还是它实际上是一个方法。下面的代码假定所有带有 type(v) == "function"
的属性实际上都是方法,这通常是正确的,但实际上可能不适用于您的特定情况。
在最坏的情况下,您可以手动维护您想要 'proxy' 的 methods/properties 列表,但这取决于您需要代理多少个 class 以及有多少个他们拥有的属性可能会变得笨拙。
local function extend(super_instance)
return setmetatable({
newMethod = newMethod, -- also could be provided via a more complicated __index
}, {
__index = function(self, k)
-- Proxy everything but `newMethod` to `super_instance`.
local super_field = super_instance[k]
if type(super_field) == "function" then
-- Assume the access is for getting a method, since it's a function.
return function(self2, ...)
assert(self == self2) -- assume it's being called like a method
return super_field(super_instance, ...)
end
end
return super_field
end,
-- similar __newindex and __add, etc. if necessary
})
end
local function createExtended(...)
return extend(createSuper(...))
end