使用Lua中的self关键字来定义类

我知道 Lua 中的 "self" 类似于 Java 中的 "this"。"this" 在 Java 中表示当前对象,但我知道 Java 是面向对象的,而 Lua 是基于原型的。有人能解释一下为什么下面的代码必须使用 "self.last" 而不是 "self" 来访问链表的当前节点吗?谢谢 :)

list = {}
list.__index = list

setmetatable(list, { __call = function(_, ...)
local t = setmetatable({length = 0}, list)
  for _, v in ipairs{...} do t:push(v) end
  return t
end })

function list:push(t)
  if self.last then
    self.last._next = t
    t._prev = self.last
    self.last = t
  else
    self.first = t
    self.last = t
  end
  self.length = self.length + 1
end
点赞
用户1517394
用户1517394

self 用于访问传递给列表的上一个参数。例如,如果您调用 list({"Hello"}, {"world"}, {"my"}, {"name"}, {"is"})list:push 会被调用 五次,每个参数调用一次。

如果没有指定 last (即 self.last)参数(对于第一个参数来说是这样),它将会将 {"Hello"} 设置为 t = {"Hello"}; t.first = t; t.last = t;(自引用表)。

对于第二个及其之后,它会告诉前一个表({"Hello"})下一个表是 {"my"},将{"my"}告知前一个表,并将当前表设置为整个“列表”的最后一个。请记住,list:push(t) 会被调用多次。这意味着 self.last 被多次调用,但是在列表被实例化后,只有一个表格(最后一个参数)位于 self.last 中,并且每个表格都记录了列表中下一个或前一个表格。

2014-12-27 13:29:29
用户3677376
用户3677376

你的程序中有两种不同的对象: 列表对象和节点。列表对象管理一个链接节点的链,并具有以下字段:

listobject = {
  length = 0,   -- 此列表对象管理的节点数
  first = nil,  -- 此列表中的第一个节点的引用;如果列表为空,则为nil
  last = nil    -- 此列表中的最后一个节点的引用;如果列表为空,则为nil
}

对第一个节点的引用对于迭代和在列表中添加前缀很有用,而 last 引用则允许有效的追加。列表对象还具有元表,以便您可以在其上调用方法:

listobject:push( {"node1"} )

除非您进行一些有趣的事情,否则 push 方法的 self 参数始终是列表对象,而不是节点。

另一方面,节点具有对链中下一个和上一个节点的引用:

node = {
  _next = nil,  -- 如果不在列表中或者是最后一个节点,可能为nil
  _prev = nil,  -- 如果不在列表中或者是第一个节点,可能为nil
  -- 还有一些数据
}

因此,在 push 方法中,要访问 self.last 来检查列表是否为空(也可以检查 self.length),如果不是,则要查找当前列表中的最后一个节点,以便将 push 传递的新节点追加到其中。当这样做时,显然必须更新链表对象中的 last(和first)引用。链表对象(在push方法中体现的self)_不是_节点链的一部分。

2014-12-28 11:18:21