56

这是一个我已经有一段时间有点恼火的问题,只是一直没有时间去寻找答案。

但是我想我至少可以问这个问题,也许有人可以解释一下。

基本上,我使用过的许多语言都使用语法糖来编写(使用来自 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没有实现这个语法糖。

4

3 回答 3

75

这只是我的猜测,但是:

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()

您可以将自赋值运算符限制为单个赋值,但您只是添加了一个人们必须知道的奇怪的极端情况。

综上所述,完全不清楚自赋值运算符是否有用到值得处理上述问题。

于 2013-12-03T21:47:45.560 回答
17

我想你可以把这个问题改写为

为什么<languageX>没有<featureY>from <languageZ>

通常,这是语言设计者根据他们对语言的用途和目标的看法而做出的权衡。

在 Lua 的情况下,该语言旨在成为一种嵌入式脚本语言,因此任何使该语言更复杂或可能使编译器/运行时稍微更大或更慢的更改都可能与此目标背道而驰。

如果你实现了每一个微小的特性,你最终会得到一种“厨房水槽”语言:ADA,有人吗?

正如你所说,它只是语法糖。

于 2013-11-20T09:32:48.000 回答
12

Lua 没有自赋值运算符的另一个原因是,表访问可以被元表重载,从而产生任意副作用。对于自我分配,您需要选择脱糖

foo.bar.baz += 2

进入

foo.bar.baz = foo.bar.baz + 2

或进入

local tmp = foo.bar
tmp.baz = tmp.baz + 2

第一个版本运行__index元方法foo两次,而第二个版本只运行一次。不包括语言中的自我分配和强迫你明确有助于避免这种歧义。

于 2014-01-03T16:22:31.543 回答