Lua表,重载__tostring的最简单方法

4
感谢所有讨论如何自定义打印表格的Lua stackoverflow用户。经过大量阅读,我发布以下内容并向Lua专家询问:
  • 这是最简单的方法吗?
  • 它是否太简单(即以我不理解的某种方式损坏)?

请注意以下内容:

  • 允许私有字段(只需以“_”开头命名),不会被打印出来
  • 不会向每个对象的metatable添加大小。

我的方法重写了默认的tostring方法。

_tostring =  _tostring or tostring
function tostring(t)
  if type(t) == "table" then 
    status, stuff = pcall(function() return t:s() end) 
    if status then 
      return stuff 
  end end 
  return _tostring(t) 
end

上面的代码有点邪恶(调用 pcall 的那部分……并不是我最引以为傲的代码,但是它能够工作)。
无论如何,现在 tostring 把方法调用 t:s() 转换为了一个我们可以使用以下自制对象系统定义的对象:
Object={}

function Object:new(o)
   o = o or {} 
   setmetatable(o,self)  
   self.__index = self
   return o
end

这是:s()的默认定义,可以在子类中进行自定义。
function Object:s()
  -- can be customized in subclasses
  local out,sep="{",":"
  for x,y in pairs(self) do 
    if string.sub(x,1,1) ~= "_" then
      out = out..sep..x.." "..y 
      sep = " :"
  end end  
  return out .. '}'
end

例如。
x=Object:new{a=1, _b=2};print(x)
{:a 1}

2
为什么要重写 tostring 而不是设置 __tostring 元方法? - warspyking
1
我投票将此问题标记为“不适合主题”,因为它展示了一段工作代码,而且 OP 正在请求 [codereview.se]。 - hjpotter92
4
“@hjpotter92工作代码”不是Stack Overflow上一个有效的离题理由。他正在寻求对特定问题/问题的改进,这在Code Review上也是离题的。 - Quill
1个回答

12

这是最简单的方式吗?

远远不是。最简单的方式是在元表中添加一个__tostring函数。

function MyClass:__tostring()
    return "<MyClass: "..self.foo..">"
end

不会向每个对象的元表添加大小。

这不是一个问题。每个类应该只存在一个元表。表中的一个条目的内存使用量可以忽略不计。

覆盖tostring既丑陋又可能带来危险:如果您(或其他人)正在使用具有副作用的s方法的库,那该怎么办?


5
请注意,Lua 5.1 中的 __tostring 不会影响对 lua_tolstring 的调用。这在 5.2 及更高版本中得到了修复。 - Nicol Bolas

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