在Lua中,你能从'self'获得一个对象名吗?

时间:2014-04-12 16:50:32

标签: class oop lua

我可能遗漏了一些非常简单的东西,但是当在Lua中调用某个对象的方法时,有没有办法从self变量中获取该对象的名称?

为了说明我的意思,这是一个有点人为的例子 - 一个简单的Stack实现:

Stack = {}
function Stack:new (...)
    instance = {}
    instance.elements = {...}
    setmetatable(instance, self)
    self.__index = self
    return instance
end
function Stack:push (...)
    for i,v in pairs({...}) do
        table.insert(self.elements,v)
    end
end
function Stack:pop ()
    if #self.elements > 0 then
        return table.remove(self.elements)
    else
        error("Cannot pop, Stack is empty")
    end
end

my_stack = Stack:new(2,4)
my_stack:push("dog")      -- my_stack.elements = {2,4,"dog"}
print(my_stack:pop())     -- "dog"
print(my_stack:pop())     -- "4"
print(my_stack:pop())     -- "2"
print(my_stack:pop())     -- error: "Cannot pop, Stack is empty"

是否可以使用self错误消息中的Stack:pop变量输出要调用的对象的名称?我希望错误消息说出" Cannot pop, Stack 'my_stack' is empty"。

2 个答案:

答案 0 :(得分:5)

  

有没有办法从自变量中获取该对象的名称?

Lua中的对象没有名称。只有引用具有名称,变量和表字段最终只是对象的引用。所以,如果你问如何获取引用的名称,显然你不能,因为可能有任意数量的引用具有不同的名称,哪一个“self.getName()”返回?

您可以为每个对象提供唯一的标识符,例如在构建时。然后new()的一个参数将是对象名称,您将其保存为self.name(例如)然后您可以根据需要访问它(我想,对于日志消息或查找内部一些关联数组)。所以你会这样做

my_stack = Stack:new("my_stack", 2,4)
my_stack:push("dog")      -- my_stack.elements = {2,4,"dog"}

我不知道如何让new()弄清楚新实例将被分配给名为my_stack的变量。事实上,我怀疑即使使用调试模块也不可能,因为只有在new返回后才会进行分配。因此没有任何东西迫使对象的名称与变量相同,这完全取决于你。它甚至不是你想要的东西,因为你可以多次引用同一个堆栈对象:

a = Stack:new("a", 2,4)
b = a  -- b and a are the same object in memory

错误消息是否应提及ab?我认为最好为对象分配一个id,然后你总是知道在错误信息中正在讨论哪个对象:

a = Stack:new("my_stack_1", 2,4)
b = a
t = { b = { c = a } }
a:push("dog") -- error will mention my_stack_1: clear which object you are referring to
t.b.c:push("dog") -- error will mention my_stack_1: still clear which object you are referring to

如果您担心错误消息,您无法确定哪个行调用new(self, "dog")debug模块可以派上用场:使用它可以获取行号和进行调用的文件,所以你可以说“对象my_stack_1:pop():堆栈中没有元素(从文件Y的第X行调用)”

答案 1 :(得分:4)

local function get_my_self_name(self)
   local i = debug.getinfo(3, 'Sl');
   return "'"..(io.open(i.source:match'@(.*)'):read'*a'
      :gsub('.-\n','',i.currentline-1)
      :match('(.-)[:.]%s*'..debug.getinfo(2,'n').name..'%s*%(')
      :match'([%w_]+)%s*$' or '<unnamed>').."' at line #"..i.currentline
end
local Stack = {}
function Stack:new (...)
   local instance = {}
   instance.elements = {...}
   setmetatable(instance, self)
   self.__index = self
   return instance
end
function Stack:push (...)
   for i,v in ipairs({...}) do
      table.insert(self.elements,v)
   end
end
function Stack:pop ()
   if #self.elements > 0 then
      return table.remove(self.elements)
   else
      error("Can't pop, Stack "..get_my_self_name(self).." is empty")
   end
end

local my_stack = Stack:new(2,4)
my_stack:push("dog")  --my_stack.elements = {2,4,"dog"}
print(my_stack:pop()) --"dog"
print(my_stack:pop()) --"4"
print(my_stack:pop()) --"2"
print(my_stack:pop()) --error: Can't pop, Stack 'my_stack' at line #35 is empty