Scala是一种有趣的语言,声称简洁,可扩展(通过在库中指定许多功能而不是编译器),并支持DSL。 在尝试实现这一目标时,它有许多运算符和编译器调整(例如,支持中缀运算符,例如:_ *以展平序列)。
我发现很多运算符('Scala编程'索引中的2½页)和编译器调整令人困惑。公平地说,许多运算符是从C等人那里借来的传统算术/布尔运算符。
我被告知支撑这个有一些基本的句法规则,我认为如果我知道这些会减少我的认知负担。
是否有一些规则(如果是的话,它们是什么)或者我注定要学习图书馆中的许多“操作员”方法和含义?
答案 0 :(得分:7)
有两种方法可以理解有关运营商的问题:
确实有规则。我会让你确定你是否认为他们中有“少数”。与Scala一样,您可以在Language Reference第6.12节中找到它们。
最重要的一点:
唯一接受的前缀运算符为+
,-
,!
和~
。
任何不带参数的方法都可以用作 postfix 运算符。
任何带有一个参数的方法都可以用作 infix 运算符。然而,这些操作的优先级受特定规则的约束,可能大部分是因为算术和其他表达式被视为人们期望的。优先级由运算符/方法名称的第一个字符确定,并与您对C或Java的期望值相匹配。
所有中缀运算符都是左关联运算符,但以:
结尾的运算符除外。典型示例包括::
和+:
。
基本上是四条规则。我鼓励您阅读规范以获得更多见解。
操作员定义的选择取决于库设计者。例如,Scala集合库使用一组相对较小且一致的运算符(++
,--
,**
,+=
,-=
,{{ 1}},++=
,--=
等)。 Parser组合器带有更具异国情调的组合,有些库最初可能是完全无法穿透的,因为他们的自定义操作员定义(想到sbt或Lift,虽然这只是我个人的意见)。
这被认为是潜在问题的根源,Scala风格指南有this来说明符号方法名称(自定义运算符):
避免!尽管Scala在多大程度上促进了API设计的这一领域,但不应轻率地定义具有符号名称的方法,尤其是当符号本身是非标准的时(例如,
+:
)。作为一般规则,符号方法名称有两个有效的用例:
- 特定于域的语言(例如
>>#>>
)- 逻辑数学运算(例如
actor1 ! Msg
或a + b
)
答案 1 :(得分:1)
Scala对运营商没有特殊待遇
摘自“Scala 2ed编程”一书
任何方法都可以是运算符
在Scala中,运算符并不特殊 语言语法:任何方法都可以是运算符。是什么让方法成为现实 运算符就是你如何使用它。当你写“s.indexOf('o')”时,indexOf 不是运营商。但是当你写“s indexOf'o'”时,indexOf就是一个 运算符,因为您在运算符表示法中使用它。
我找不到您所指的索引中的2 1/2页。
Scala运算符始终可用作某些对象上定义的方法。这与以下事实一致:任何值都表示为scala中的对象,与原始类型的java特殊遗留处理不同。
scala底层实现可以在字节码级别使用基元来提高性能,但这对最终用户来说是透明的。
<强>算强>
所以这里的规则很简单:每个运算符实际上都是某种类型的定义方法。运算符中缀符号只是一个可读性问题,例如
val sum = 1 + 2
比
读得更好val sum = 1.+(2)
这种表示法也是构建具有“自然感觉”的dsl的基础。测试库ScalaSpecs清楚地证明了这一点。
特殊编译器规则
正如你所说,有一些有限的“编译器调整”可用于上述目的,即允许更清晰,更易理解的代码。
这些“调整”的相关摘要可以找到here
答案 2 :(得分:1)
所有信息均可在stackoverflow和spec中找到。
以下是我的建议:
+
,-
,*
,/
的那些,字母具有最低优先级,而奇怪的unicode具有最高优先级。对于其余部分,我添加括号或者只是猜测优先级将像DSL设计者在Java中所期望的那样“解决”。x :: xs
和xs ::: ys
运算符,因为它们非常流行且与右侧相关联,因为它们以:
结尾。 =
和前缀运算符的运算符的细节。 最后,最后一句忠告。不要试图学习所有操作员,不要认为你应该知道所有操作员的意思,以有效地使用该语言。这是除非您通过阅读和记住完整的API学习了其他语言。