lua工具库penlight--09技术选择

 

模块化和粒度

在理想的世界,一个程序应该只加载它需要的库。Penlight需要额外100 Kb 的字节码工作。它是简单但却乏味要加载你需要什么:

 local data = require 'pl.data'

 local List = require 'pl.List'

 local array2d = require 'pl.array2d'

 local seq = require 'pl.seq'

 local utils = require 'pl.utils'

 

这是我在Penlight里一直保持的风格,这样模块不会破坏全局环境 ;此外, stringx.import()没有使用是因为它将更新全局字符串表。

 

但在脚本里require ‘pl’是更方便问题是如何保证一个不加载整个库,而且方便。该战略是仅在引用它们的时候加载模块。在 'init.lua' require ‘pl’时加载里,元表附加到具有__index metamethod 的全局表。任何未知名称的会在模块列表中查找,如果找到,我们加载它,并使该模块全局可用。所以当遇到tablex.deepcompare时, tablex会引起 'pl.tablex'加载.

 

修改全局表的行为造成后果。例如,著名的strict模块,也包括 Lua 本身 (也许是Lua 本身写的唯一 Lua标准模块),也不会修改这样,全局变量在使用之前必须定义 。所以 'init.lua' 允许未找到子,正是'pl.strict.lua' 使用。其他库可能会安装自己_Gmetatables,但Penlight现在会将任何未知的名称转发到原始的__index元表。

 

但是该战略还得努力: 旧 '厨房水槽' 'init.lua' 引入大约 260 K 的字节码,而现在典型的程序使用约 100 K 和短的脚本更 — — 例如,如果他们只需要在utils中的功能 .

 

有一些函数把它们的输出表标记为特殊的元表,这样看起来很合适。例如,tablex.makeset 创建一个Set  seq.copy创建一个List 。但这并不导致自动加载pl.Set pl.List;只有当您尝试访问的它们的任意方法。在 'utils.lua',有一个叫stdmt的导出表:

 stdmt = { List = {}, Map = {}, Set = {}, MultiMap = {} }

 

如果你去查看'init.lua',这些普通的小 '识别获取__index metamethod ,来强制加载全部功能。这里是来自 'list.lua' 启动list的代码:

 List = utils.stdmt.List

 List.__index = List

 List._name = "List"

 List._class = List

 

“按需加载”战略帮助模块化。特别是对于随便使用,require ‘pl’是方便和模块化的折衷。

在当前版本中,我减少了奇技淫巧。以前,Map 被定义在pl.class ;现在它明智地定义pl.Map ;pl.class只包含基本类机制 (并返回该函数。为保持一致性,List 直接由require ‘pl.List’ (注意大写的 'L')返回,此外,减少了像pl.config的非核心库中的模块依赖关系。

 

定义什么调用

'utils.lua' 导出的function_arg 整个Penlight广泛使用。它定义了什么是 '可调用'。显然 函数传递立即回。但字符串呢?第一个选项是它表示在 'operator.lua'中的运算符这样 ' <' 是只是operator.lt 别名.

 

然后,我们检查是否有元表定义的函数工厂

(字符串可回是真的但在实践中这变成了一个可爱但半信半疑的想法,因为所有字符串都共享同一个元表。一个常见的编程错误是将错误类型的对象传递给一个函数。获得一个干净的'试图调用字符串消息比一些晦涩的跟踪要好)。

 

注册一个函数工厂的其他模块是pl.func  。占位符表达式不能直接调用,因此需要被实例化和缓存,以作为可能有效的方式。

(不一致的情况是, utils.is_callable此进行彻底的检查。

 

原文地址:https://www.cnblogs.com/xdao/p/lua_penlight09.html