装饰器和文档字符串

lua-users home
wiki

模式:装饰器、注解器和文档字符串

有时我们想将一些元数据与对象关联起来,例如对象的文档或类型信息。可以将其存储在对象内部的一个字段中,从而修改对象实现,但这可能是需要避免的,尤其是当对象属于他人时(信息隐藏)。实际上,如果对象是函数或只读表,则可能无法修改对象。

一种解决方案基本上是创建一个全局表,将对象(作为键)映射到它们的注解(作为值)。根据定义,对象具有唯一的标识,因此可以用作表中的唯一键。这样,对象本身就不会被修改。这会稍微干扰垃圾回收,因为全局表会持有对象的引用,但我们可以为此目的在 Lua 中使用“弱表”(请参阅《Lua 编程》一书中的 LuaBooks)。

这是将文档字符串 [1] 应用于 Lua 对象的一种方法。

local docstrings = setmetatable({}, {__mode = "kv"})
 
function document(str)
  return function(obj) docstrings[obj] = str; return obj end
end
 
function help(obj)
  print(docstrings[obj])
end
 
document[[Print the documentation for a given object]](help)
document[[Add a string as documentation for an object]](document)
 
f = document[[Print a hello message]](
  function()
    print("hello")
  end
)
f()
help(f)

注意:如果注解对象本身引用了它所注解的对象,则垃圾回收可能会失败(请参阅 GarbageCollectingWeakTables)。

Perl 的“内部对象”模式应用了某种程度上类似的模式。

此模式可应用于其他情况,您希望将元数据应用于对象而不对这些对象进行任何更改。这些包括 Python 中使用的函数装饰器 [2] [3]

以下应用于函数装饰器的替代语法可能更受欢迎

random =
  docstring[[Compute random number.]] ..
  typecheck("number", '->', "number") ..
  function(n)
    return math.random(n)
  end

函数装饰器基本上可以这样实现

mt = {__concat =
  function(a,f)
    return function(...)
      print("decorator", table.concat(a, ","), ...)
      return f(...)
    end
  end
}

function typecheck(...)
  return setmetatable({...}, mt)
end

function docstring(...)
  return setmetatable({...}, mt)
end

这里在函数装饰器和函数之间使用运算符(..)避免了函数周围的括号,并使得链接装饰器更方便。我们希望此运算符具有右结合性,因此此运算符的唯一选择是 ..^

另请参阅 LuaTypeChecking,了解装饰器在表示函数参数和返回类型方面的具体用途。

--DavidManura, 2007-02


RecentChanges · preferences
编辑 · 历史
最后编辑于 2009 年 5 月 1 日下午 8:26 GMT (diff)