装饰器和文档字符串

lua-users home
wiki

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

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

一种解决方案是创建一个全局表,将对象(作为键)映射到它们的注释(作为值)。根据定义,对象具有唯一的标识,因此可以作为表中的唯一键。这样,对象本身不会被修改。这会对垃圾回收造成一些干扰,因为全局表保存了对对象的引用,但我们可以为此目的在 Lua 中使用“弱表”(参见《Programming in 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 年 2 月


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009 年 5 月 2 日凌晨 2:26 GMT (差异)