如何在 Lua 中创建一个简单的可导入 class?
How to create a simple importable class in Lua?
我想在单独的文件 myclass.lua 中的 Lua 中创建 MyClass
class,我可以将其导入并在以后使用。
它应该按以下方式工作:
local MyClass = require 'myclass'
tab = {1,2,3}
m = MyClass(tab)
但是,按照 Lua 文档中的代码,我无法使其正常工作并且出现错误 attempt to call global 'MyClass' (a table value)
。
到目前为止我为 myclass.lua 编写的代码:
local MyClass = {}
MyClass.__index = MyClass
function MyClass.__init(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
有很多示例如何在 Lua 中编写 classes,但我不认为我理解其中的区别,因此在实现细节中迷失了方向。是否有或多或少的常规方法来做到这一点?
没有 __init
元方法可用于 table。当您执行以下操作时:
m = MyClass(tab)
它查找 MyClass.__call
方法定义。只需将您的 myclass.lua
更新为:
local MyClass = {}
MyClass.__index = MyClass
function MyClass:__call(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
在 Lua 中,您通常不能像调用函数那样调用 table。例如,此代码将产生 "attempt to call local 't' (a table value)".
的错误
local t = {}
t()
不过,有一种方法可以通过使用元tables 来完成这项工作。
local hello = {}
local mt = {} -- The metatable
mt.__call = function ()
print("Hello!")
end
setmetatable(hello, mt)
hello() -- prints "Hello!"
当您尝试像调用函数一样调用 table 时,Lua 首先检查 table 是否有元 table。如果是,则它会尝试调用该元 table 的 __call
属性 中的函数。 __call
函数的第一个参数是 table 本身,后续参数是 table 作为函数调用时传递的参数。如果 table 没有 metatable,或者 metatable 没有 __call
函数,则会引发 "attempt to call local 't'" 错误。
您的示例代码存在三个问题:
- 您正在尝试使用
__init
而不是 __call
。 Lua 没有 __init
元方法。
__call
采用与您使用的参数不同的参数。 __call
函数的第一个参数是 table 本身。您可以使用 function MyClass.__call(self, tab)
,或使用冒号语法 function MyClass:__call(tab)
,它会隐式地为您添加 self
参数。这两种语法在功能上是相同的。
- 您还没有为
MyClass
table 设置元table。当您为 MyClass 的对象设置 metatable 时,这并不意味着会自动为 MyClass 本身设置 metatable。
要解决此问题,您可以执行以下操作:
local MyClass = {}
setmetatable(MyClass, MyClass)
MyClass.__index = MyClass
function MyClass:__call(tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, MyClass)
return obj
end
return MyClass
这会将 MyClass 设置为将自身用作元table,这是完全有效的Lua。
metatables 的系统非常灵活,允许您拥有几乎任何您想要的 class/object 方案。例如,如果您愿意,您可以内联完成所有操作。
local MyClass = {}
setmetatable(MyClass, {
__call = function (class, tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, {
__index = MyClass
})
return obj
end
})
return MyClass
除了简洁之外,这还有一个好处,即如果人们可以访问 class table,则他们无法更改 class 的元方法。
我想在单独的文件 myclass.lua 中的 Lua 中创建 MyClass
class,我可以将其导入并在以后使用。
它应该按以下方式工作:
local MyClass = require 'myclass'
tab = {1,2,3}
m = MyClass(tab)
但是,按照 Lua 文档中的代码,我无法使其正常工作并且出现错误 attempt to call global 'MyClass' (a table value)
。
到目前为止我为 myclass.lua 编写的代码:
local MyClass = {}
MyClass.__index = MyClass
function MyClass.__init(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
有很多示例如何在 Lua 中编写 classes,但我不认为我理解其中的区别,因此在实现细节中迷失了方向。是否有或多或少的常规方法来做到这一点?
没有 __init
元方法可用于 table。当您执行以下操作时:
m = MyClass(tab)
它查找 MyClass.__call
方法定义。只需将您的 myclass.lua
更新为:
local MyClass = {}
MyClass.__index = MyClass
function MyClass:__call(tab)
self.tab = tab or {}
setmetatable({},MyClass)
return self
end
return MyClass
在 Lua 中,您通常不能像调用函数那样调用 table。例如,此代码将产生 "attempt to call local 't' (a table value)".
的错误local t = {}
t()
不过,有一种方法可以通过使用元tables 来完成这项工作。
local hello = {}
local mt = {} -- The metatable
mt.__call = function ()
print("Hello!")
end
setmetatable(hello, mt)
hello() -- prints "Hello!"
当您尝试像调用函数一样调用 table 时,Lua 首先检查 table 是否有元 table。如果是,则它会尝试调用该元 table 的 __call
属性 中的函数。 __call
函数的第一个参数是 table 本身,后续参数是 table 作为函数调用时传递的参数。如果 table 没有 metatable,或者 metatable 没有 __call
函数,则会引发 "attempt to call local 't'" 错误。
您的示例代码存在三个问题:
- 您正在尝试使用
__init
而不是__call
。 Lua 没有__init
元方法。 __call
采用与您使用的参数不同的参数。__call
函数的第一个参数是 table 本身。您可以使用function MyClass.__call(self, tab)
,或使用冒号语法function MyClass:__call(tab)
,它会隐式地为您添加self
参数。这两种语法在功能上是相同的。- 您还没有为
MyClass
table 设置元table。当您为 MyClass 的对象设置 metatable 时,这并不意味着会自动为 MyClass 本身设置 metatable。
要解决此问题,您可以执行以下操作:
local MyClass = {}
setmetatable(MyClass, MyClass)
MyClass.__index = MyClass
function MyClass:__call(tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, MyClass)
return obj
end
return MyClass
这会将 MyClass 设置为将自身用作元table,这是完全有效的Lua。
metatables 的系统非常灵活,允许您拥有几乎任何您想要的 class/object 方案。例如,如果您愿意,您可以内联完成所有操作。
local MyClass = {}
setmetatable(MyClass, {
__call = function (class, tab)
local obj = {}
obj.tab = tab or {}
setmetatable(obj, {
__index = MyClass
})
return obj
end
})
return MyClass
除了简洁之外,这还有一个好处,即如果人们可以访问 class table,则他们无法更改 class 的元方法。