我正在尝试在Lua脚本中实现对象表示法。 以下是我成功使用C API的方法:
我创建了一个新的全局表“Test”作为一个类,并在其中添加了一个字段“new”,指向一个用C编写的函数 即我可以用lua代码执行此操作:“local obj = Test.new()”(它调用函数“new”)
“new”C函数创建并返回一个新表,并将函数作为字段注册(例如“add”,“count”......) 即我可以这样做:“obj:add(”mike“)”和“obj:count()”(obj作为第一个参数传递,带有“:”符号)
2个问题:
1)一切都按预期工作,但我想知道的是:在我的情况下使用metatables有什么好处? 我到处看到metatables可以帮助我实现我想要做的事情,但我不明白它们会在哪里有用? 作为方法向表添加字段是不正确的? metatables如何帮助我(如果作为我的表格metatables添加)?
2)实际上我试图在这里重现Lua中C ++的行为。 例如,当我用C ++编写时:“Test * obj = new Test();” 我希望C ++和Test的构造函数能够返回一个Test实例的指针。 这正是我在尝试Lua为我做的事。
问题是我在这种情况下使用表,作为“new”的返回,但不是指针,所以我可以稍后用Lua(使用其字段)调用方法,就像标准C ++对象一样运营商 - >)。
为了能够在C语言中检索我的类的实际指针,我在“new”返回的表中添加了一个字段“ptr”(light uservalue)。没有它,我本来只能操作我的C函数中的Lua表,仅此而已(因此没有更多的方法调用实际指针)。
我的第二个问题是,这是正确的方法吗? 如果没有这个“ptr”字段,你是否能更好地掌握如何在任何地方操纵我的指针?
谢谢,
尼古拉斯。
答案 0 :(得分:3)
在我的案例中使用元表的优点是什么?
这是一个。
Test.new = function() end
我刚刚破坏了您在全球范围内创建新Test
个对象的能力。如果您使用metatable保护Test
,我必须真正努力才能做到这一点。
这是另一个:
local myTest = Test()
如果没有metatable(重载__call
metamethod),你就无法做到这一点。 Lua语法看起来比调用Test.new
更自然。
另一个:
local testAdd = Test() + Test()
运营商重载。没有元数据就不能这样做。
此外:
这正是我在尝试Lua为我做的事。
这是一个提示:不要。
出于某种原因,不同的语言是不同的。你应该用Lua Lua 方式做事,而不是C ++方式。我可以理解想要提供某些C ++机制(比如重载等),但是你不应该使用new
只是因为那是C ++使用的。
答案 1 :(得分:3)
主要原因是你得到了__index元方法。 没有它,对象的每个实例都必须具有与之关联的所有函数:这可以使表大小;并使用大量内存。
local methods = {
foo = function() return "foo" end ;
bar = function() return "bar" end ;
bob = function() return "bob" end ;
hen = function() return "hen" end ;
}
所以你有
function new_no_mt ( )
local t = {}
for k , v in pairs ( methods ) do t [ k ] = v end
return t
end
VS
local mt = { __index = methods ; }
function new_mt ( )
return setmetatable ( { } , mt )
end
还有其他好处;
否则,您尝试做的事情听起来像是userdata的完美情况。 只有当你有__index metatmethod(没有表放入方法)时,才能对userdata编制索引。