在Lua中使用metatables

时间:2011-11-17 21:28:59

标签: lua

我正在尝试在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”字段,你是否能更好地掌握如何在任何地方操纵我的指针?

谢谢,

尼古拉斯。

2 个答案:

答案 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 ++使用的。

此外,还有很多图书馆可供您使用。 SWIGLuabind是两个大问题。

答案 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

还有其他好处;

  • 定义运算符;
  • 通过比较元表来轻松进行类型比较。
  • 更改metatable中的方法会更改所有对象的方法,但在一个对象上更改它只会更改该对象。

否则,您尝试做的事情听起来像是userdata的完美情况。 只有当你有__index metatmethod(没有表放入方法)时,才能对userdata编制索引。