默认局部变量 |
|
Lua 的声明被描述为“默认全局”,这与“默认局部”(Python 和 Ruby)形成对比。另一种选择是没有任何东西是“默认的”(即要求显式声明局部变量和全局变量)。以下是一些关于此的深刻引述:
[4] “默认局部是错误的。也许默认全局也是错误的,[但是] 解决方案不是默认局部。” (Roberto)
[5] “我真的不明白为什么任何人会想要变量默认是*任何东西*,就像自动声明一样。它只是偶尔为你节省几个按键,同时为寻找愚蠢的、难以发现的拼写错误和名称混淆错误打开了无限的乐趣。(赋值代替声明,反之亦然。)” (David Olofson)
[6] “问题在于,没有[显式]局部声明,你就无法说明变量是在哪里局部的。” (RiciLake)
[7] “‘默认局部’与词法作用域不兼容……正确的词法作用域真正要求你可以在修改绑定(赋值)和创建新绑定(声明)之间进行选择。唉,‘默认局部’规则混合了它们,并使赋值同时完成这两件事。” (MikePall)
[8] “在我看来,默认局部变量的主要论点是防止全局环境中的意外,其次是使声明局部变量成为可选的,从而减少输入。我个人认为,使声明成为可选是一个坏主意,无论是对局部变量还是全局变量。为了强制对全局变量进行显式声明,以及防止全局环境中的意外,我使用 `require 'strict'`。也许可以在编译时做一些等效的(或更好的)事情。但我的重点是,也许应该问自己,你是否真的想要/需要默认局部变量,或者只是显式的全局声明。” (Mark Meijer)
[Python PEP 3104] -- Python 对“默认局部”的修复,这与 ReubenThomas 的提议(见下文)是相同的(除了关键字的选择!)。
[1] “[当前的局部变量作用域规则] 是 Ruby 中最大的设计缺陷。” (Yukihiro Matsumoto, Ruby 设计师) (评论:[9][10][7])
[2] -- 关于各种作用域规则的讨论,以及为什么 Converge 语言选择了“默认局部”并带有“非局部”(类似 PEP 3104)关键字。(Laurence Tratt, Converge 设计师)
[3] “我不喜欢隐式声明词法变量,因为它往往会破坏它们的主要用途,即捕获拼写错误……声明应该像声明……我相信用 `my` 声明是经过良好霍夫曼编码的。” (Larry Wall, Perl 设计师)
以下是另一个“默认局部”的提案。在我看来,它比其他提案更简单,更不显眼,却能提供更好的结果。(-- ReubenThomas)
更改包括:
1. 添加一个新的关键字“outer”,其作用类似于“local”,但它声明给定名称指向一个包围函数中同名的最内层变量,或者,如果没有,则指向一个同名的全局变量(即使该全局变量当前不存在)。
2. 函数中对变量的首次赋值隐式地充当“local”声明,除非该变量已在该函数中显式或隐式声明过。函数外部的赋值按原样工作,对表元素的赋值也是如此。
注意
a. 能够进行配置文件风格的全局赋值得以保留,但代价是函数内的赋值方式与函数外部不同。实际上这不应该成为问题,因为很少有 Lua 脚本在顶层包含复杂的代码。如果你需要在顶层代码中使用局部变量,你只需像现在一样声明它们。
b. 语法上唯一的改变是添加了“outer”(类似于其他提案中使用的“nonlocal”、“extern”或“static”关键字,用于声明这些不在词法作用域或任何闭包中定义的符号的使用)。
c. 语义上唯一的改变是函数内赋值的含义。
d. 赋值只使变量在发生赋值的地方局部化,而不是在整个函数中局部化。这符合最小惊讶原则:你不需要阅读整个函数来确定某个变量是否是局部的(编译器也不需要,所以实现很简单)。