Lua运算符,为啥不定义+=、-=等?
Posted
技术标签:
【中文标题】Lua运算符,为啥不定义+=、-=等?【英文标题】:Lua operators, why isn't +=, -= and so on defined?Lua运算符,为什么不定义+=、-=等? 【发布时间】:2013-12-04 04:48:01 【问题描述】:这是一个我已经有一段时间有点恼火的问题,只是一直没有时间去寻找答案。
但我想我至少可以提出这个问题,也许有人可以解释一下。
基本上我使用过的许多语言都使用语法糖来编写(使用来自 C++ 的语法):
int main()
int a = 2;
a += 3; // a=a+3
虽然在 lua 中 +=
没有定义,所以我必须写 a=a+3
,这又是关于语法糖的。当使用更“有意义”的变量名时,例如:bleed_damage_over_time
或者写起来变得乏味的东西:
bleed_damage_over_time = bleed_damage_over_time + added_bleed_damage_over_time
代替:
bleed_damage_over_time += added_bleed_damage_over_time
所以如果你没有一个好的解决方案,我想知道如何解决这个问题,在这种情况下,我当然有兴趣听到它;而是为什么 lua 没有实现这种语法糖。
【问题讨论】:
至少有一个第 3 方补丁实现了这一点:lua-users.org/wiki/LuaPowerPatches(向下滚动到“复合赋值运算符 (5.2)”) 为什么 C 不支持类?为什么我不能在 C 中使用int a = b = c = 0;
?为什么 C++ 中没有像 int a, float b, char *c = 1, 2.22, "3rd string";
这样的分配?无意冒犯,但每种语言都有其自身的局限性和优势。
@hjpotter92 完全没有冒犯,你回答了我提出的问题,证明这正是我想要的。 -> +1
顺便说一句,如果您正在寻找一些不错的 lua 语法扩展,请查看 moonscript (github.com/leafo/moonscript),它是一个元编程库,可通过以下方式扩展 Lua 语法这样的事情,它在幕后生成 Lua。
顺便说一句,像这样的长变量名表明您没有使用适当的数据结构和/或没有将函数范围限定为合理的大小。变量名称应该是描述性的在它们的上下文中。
【参考方案1】:
这只是我的猜测,但是:
1.在单遍编译器中很难实现这一点
Lua 的字节码编译器实现为单遍递归下降解析器,可立即生成代码。它不会解析为单独的 AST 结构,然后在第二次传递中将其转换为字节码。
这对语法和语义施加了一些限制。特别是,任何需要任意前瞻或前向引用的东西都很难在这个模型中得到支持。这意味着分配已经很难解析。给定类似的东西:
foo.bar.baz = "value"
当您解析foo.bar.baz
时,您并没有意识到您实际上是在解析一个赋值,直到您已经解析并生成了代码之后点击了=
。正因为如此,Lua 的编译器在处理赋值方面有相当多的复杂性。
支持自我分配会使这变得更加困难。比如:
foo.bar.baz += "value"
需要翻译成:
foo.bar.baz = foo.bar.baz + "value"
但是当编译器遇到=
时,它已经忘记了foo.bar.baz
。这是可能的,但并不容易。
2。它可能不适合语法
Lua 在语法中实际上没有任何语句或行分隔符。空格被忽略,并且没有强制分号。你可以这样做:
io.write("one")
io.write("two")
或者:
io.write("one") io.write("two")
Lua 对两者都同样满意。保持这样一个明确的语法是很棘手的。我不确定,但自赋值运算符可能会使这变得更难。
3.多重分配效果不好
Lua 支持多重赋值,比如:
a, b, c = someFnThatReturnsThreeValues()
我什至不清楚如果你尝试这样做意味着什么:
a, b, c += someFnThatReturnsThreeValues()
您可以将自赋值运算符限制为单个赋值,但您只是添加了一个人们必须知道的奇怪的极端情况。
综上所述,自赋值运算符是否有用到值得处理上述问题还不是很清楚。
【讨论】:
非常感谢您花时间回答。您确实为我的问题指出了一些非常合理且可能的论点。我只是接受它只是一个糟糕的问题。但是在阅读了您的答案后,我觉得我更了解并给出了所有论点,甚至同意 Lua 不尝试提供这些运算符。 不客气!这些东西让我记忆犹新,因为我目前正在实现一种语言,它也有一个单通道编译器,它迫使我意识到它是如何影响它的设计的。 有人提到递归下降编译器和解析赋值语句的问题?我很清楚,但问题主要在于解析 LHS。如果您可以可靠地找到赋值运算符并理解 LHS,那么操作树以生成 '+=' 或等价物并不难。在没有树的情况下做这件事,现在更难了。 1. 但是已经有一个这种类型的运算符,:
。它用于调用函数,同时自动将您使用它的表作为第一个参数传递,就像+=
和朋友一样。 2. 这没有任何意义。为什么行分离与它有关?它与普通赋值运算符=
具有相同的语法。 3. 这听起来很清楚。你想增加所有三个。
不幸的是,源文件没有很好的记录。 “原型”是 Lua 用来指代一个函数在被封装到闭包之前的编译内部表示。这是一个没有上值的函数。【参考方案2】:
我想你可以把这个问题改写成
为什么
<languageX>
没有来自<languageZ>
的<featureY>
?
通常,这是语言设计者根据他们对语言用途的愿景和目标做出的权衡。
在 Lua 的情况下,该语言旨在成为一种嵌入式脚本语言,因此任何使该语言更复杂或可能使编译器/运行时稍微更大或更慢的更改都可能与此目标背道而驰。
如果你实现了每一个微小的功能,你最终会得到一种“厨房水槽”语言:ADA,有人吗?
正如你所说,它只是语法糖。
【讨论】:
感谢您的回答,它确实提供了我想要的信息。这确实有道理,我喜欢你如何展示问题的一般形式,从而将其放在透视图中。【参考方案3】:Lua 没有自赋值运算符的另一个原因是,表访问可能被元表重载,从而产生任意副作用。对于自我分配,您需要选择脱糖
foo.bar.baz += 2
进入
foo.bar.baz = foo.bar.baz + 2
或进入
local tmp = foo.bar
tmp.baz = tmp.baz + 2
第一个版本为foo
运行__index
元方法两次,而第二个版本只运行一次。不包括语言中的自我分配和强迫你明确有助于避免这种歧义。
【讨论】:
第二个选项会更明智,比如do local t=foo.bar t.baz=t.baz+2 end
。
:
是 Lua 中一个非常相似的运算符,但不是那样工作的。它只调用了一次__index
,值被使用了两次。以上是关于Lua运算符,为啥不定义+=、-=等?的主要内容,如果未能解决你的问题,请参考以下文章