通过C API实例化Lua对象

3

我正在尝试通过C API在Lua中实现一些面向对象的功能。在我的Lua脚本中,我有以下内容:

Parser = {}
Parser.__index = Parser

function Parser:create(url)
    local self = {}
    print ("creating")
    self.baseUrl = url
    setmetatable(self, Parser)
    return self
end

function Parser:Foo()
    print ("baseUrl: " .. self.baseUrl)
end

p = Parser:create("http://www.google.com")
p:Foo()

如果我从命令行运行它,它能正常工作并显示以下输出:

creating
baseUrl: http://www.google.com

现在,如果我注释掉最后两行并尝试通过C API执行以下操作

// <load the state and lua file>
lua_getglobal(L, "Parser");
lua_getfield(L, -1, "create");
lua_pushstring(L, "http://www.google.com");

if (lua_pcall(L, 1, 1, 0) != 0)
{
  // handle error
}

这个可行。我在标准输出中看到了预期的“creating”。据我所知,新的解析器对象现在位于堆栈的顶部。如果我立即尝试以下操作:

lua_getfield(L, -1, "Foo");
if (lua_pcall(L, 0, 0, 0) != 0)
{
  logger()->error("-- %1", lua_tostring(L, -1));
}

我看到如下错误信息:尝试对本地变量'self'进行索引(一个空值) 请问有人能告诉我我做错了什么,以及如何使函数按预期运行吗?
谢谢!
1个回答

2

function Parser.Foo(self) ... end的定义与以下代码等效:

Parser.Foo = function(self)
    print ("baseUrl: " .. self.baseUrl)
end

这意味着 — Foo 是一个需要一个参数的函数。当你调用 lua_pcall(L, 0, 0, 0) 时,你没有传递任何参数。把它改为 lua_pcall(L, 1, 0, 0) 就可以了。(你还需要将 pcall 改为 create,以正确地传递 2 个参数而不是 1 个参数)。


也就是说,a:method(...) 总是等价于 a.method(self, ...) - user308323
更准确地说,函数调用 a:method(params) 总是等价于 a.method(a,params)(除了 a 只被计算一次),而 函数定义 function a:method(params) body end 总是等价于 a.method = function(self, params) body end - Mankarse
哦,该死,我忘记了那些function。看来我甚至不能再编辑第一个评论了。 - user308323
我理解为什么调用Foo需要传递self,但在这个例子中,create是否真的需要它呢?当我调用它时,它会返回一个self - Addy
@Addy: create是一个接受两个参数--selfurl的函数。如果你想让它成为一个只接受一个参数的函数,在定义/使用时不要使用冒号语法(也就是,将其定义为Parser.create = function(url) ... end)。 - Mankarse
1
@Addy:进一步解释一下,除了它是冒号语法引入的隐式参数的名称之外,self 没有什么特别之处。你对 create 的定义只是声明了一个新变量叫做 self,这个变量掩盖了 self 函数参数的含义。 - Mankarse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接