【问题标题】:Why make global Lua functions local?为什么要让全局 Lua 函数本地化?
【发布时间】:2012-03-01 04:54:21
【问题描述】:

一直在看一些Lua源码,经常在文件开头看到这样的东西:

local setmetatable, getmetatable, etc.. = setmetatable, getmetatable, etc..

他们是否只将函数本地化以让 Lua 在经常使用时更快地访问它们?

【问题讨论】:

标签: function scope lua


【解决方案1】:

本地数据在堆栈中,因此它们确实可以更快地访问它们。但是,我严重怀疑 setmetatable 的函数调用时间实际上对于某些程序来说是一个重大问题。

以下是可能的解释:

  1. 防止污染全球环境。模块的现代 Lua 约定是不让它们直接将自己注册到全局表中。他们应该建立一个本地函数表并返回它们。因此,访问它们的唯一方法是使用局部变量。这迫使许多事情:

    1. 一个模块不能意外覆盖另一个模块的功能。

    2. 如果模块不小心这样做了,模块返回的表中的原始函数仍然可以访问。只有使用local modname = require "modname",您才能保证准确且仅获得该模块公开的内容。

    3. 包含其他模块的模块不能相互干扰。您从require 返回的表始终是模块存储的内容。

  2. 阅读“local 变量的访问速度更快”的人过早地进行了优化,然后决定让一切都变得local

一般来说,这是一种很好的做法。好吧,除非是因为 #2。

【讨论】:

  • 3.使认为调用 rawset 或 ipairs 等内置函数不好的 linter 静音。
【解决方案2】:

除了尼可波拉斯的回答,我想补充第三点:

  • 它允许您的代码在加载后在沙箱中运行。

如果函数已从沙箱中排除,并且代码是从沙箱中加载的,则它将无法工作。但是如果先加载代码,沙箱就可以调用加载的代码,并能够从沙箱中排除setmetatable等。

【讨论】:

    【解决方案3】:

    我这样做是因为它可以让我看到我的每个模块使用的功能

    此外,它还可以保护您免受他人在全球环境中更改功能的影响。 这是一个免费的(过早的)优化是一个奖励。

    【讨论】:

    • 没有什么可以阻止您的模块使用不在该列表中的函数。因此,如果您突然需要一个全局函数并且忘记将其添加到列表中,那么您正在使用全局函数。此外,如果有人更改了全局函数,那么他们这样做可能有一个好的理由,例如监控某些函数的使用等等。
    • 其实有;我有一个预提交钩子,它使用 luac 搜索 GETGLOBAL 操作码并警告我。
    • 实现这么简单的东西需要做很多工作。您刚刚使用环境为每个函数提供了特定的全局空间,因此它们不会影响其他人的。 《Lua 编程》一书将告诉你如何做到这一点。
    • 最好不要使用全局变量;特别是在大型程序或编写库时;即使被限制在环境中。通过检查 GETGLOBAL,我还经常发现在重构中遗漏了拼写错误和代码;总体而言,这是一种更好的编码方式。
    • 同样,可以通过设置适当的环境来防止全局变量。解析某些特定操作码的已编译源代码比仅正确设置环境要困难得多。此外,您不必在所有脚本中都添加巨大的序言。
    【解决方案4】:

    另一个微妙的好处:它清楚地记录了模块导入了哪些变量(函数、模块)。如果你使用 module 语句,它会强制执行这样的声明,因为全局环境被替换(所以全局变量不可用)。

    【讨论】:

      猜你喜欢
      • 2016-01-01
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 2012-08-08
      • 2017-07-06
      • 1970-01-01
      相关资源
      最近更新 更多