【问题标题】:Does Scala have a small number of underlying syntactic features?Scala 是否有少量的底层语法特性?
【发布时间】:2012-10-30 13:33:01
【问题描述】:

Scala 是一种有趣的语言,它声称简洁、可扩展(通过在库中而不是在编译器中指定许多特性)并支持 DSL。 为了实现这一点,它有很多运算符和编译器调整(例如,支持中缀运算符,例如:_* 来展平序列)。

我发现许多运算符(“Scala 编程”索引中的 2½ 页)和编译器调整令人困惑。公平地说,许多运算符都是常规算术/布尔运算符,借用自 C 等)。

有人告诉我,这有一些基本的句法规则作为基础,我认为如果我知道这些,就会减轻我的认知负担。

是否有一些规则(如果有,它们是什么)还是我注定要学习库中的许多“运算符”方法和隐式?

【问题讨论】:

    标签: scala


    【解决方案1】:

    有两种方法可以理解您关于运营商的问题:

    1. 控制 Scala 编译器如何处理运算符的规则是什么? (语言规则)
    2. 管理库中如何定义运算符的规则是什么? (运营商定义)

    语言规则

    确实有规则。我会让你确定你是否认为它们“很少”。与 Scala 一样,您可以在 Language Reference,第 6.12 节中找到它们。

    最重要的一点:

    • 唯一接受的前缀运算符是+-!~

    • 任何不带参数的方法都可以用作后缀运算符。

    • 任何采用一个参数的方法都可以用作中缀运算符。然而,这些操作的优先级受制于特定规则,可能主要是为了使算术和其他表达式被视为人们所期望的。优先级由运算符/方法名称的第一个字符确定,并且与您对 C 或 Java 的期望相匹配。

    • 所有中缀运算符都是左结合运算符,以 : 结尾的运算符除外。典型示例包括::+:

    基本上是四个规则。我鼓励您阅读规范以获得更多信息。

    运算符定义

    运算符定义的选择取决于库设计者。例如,Scala 集合库使用一组相对较小且一致的运算符(++--**+=-=++=--=+:、等等。)。解析器组合器带有一个更奇特的集合,一些库一开始可能完全无法理解,因为它们的自定义运算符定义(想到 sbt 或 Lift,尽管这只是我个人的看法)。

    这已被认为是潜在问题的根源,Scala 风格指南中有this 来说明符号方法名称(自定义运算符):

    避免!尽管 Scala 在某种程度上促进了 API 设计的这一领域,但不应轻易定义具有符号名称的方法,尤其是当符号本身是非标准的时(例如,>>#>>)。作为一般规则,符号方法名称有两个有效的用例:

    • 特定领域的语言(例如actor1 ! Msg
    • 逻辑数学运算(例如a + bc :: d

    【讨论】:

    • 谢谢,这是一个很棒的总结和我一直在寻找的东西!我已经设法避免使用 Java 语言参考 12 年和“等”。关于集合运营商的名单有点令人担忧。也许这证实了我对 Scala 是计算机科学家的语言的担忧;-)
    【解决方案2】:

    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

    【讨论】:

    • 不完全正确。它确实为了保留我们都习惯的优先规则而专门对待某些运算符。 5 + 4 * 3 真的是 5.+(4.*(3))。另见以: 结尾的右结合运算符,例如::+:
    • 运算符优先级在规范中定义,另请参阅here。关联性规则在我已经提到的摘要中
    【解决方案3】:

    所有信息都可以在stackoverflowspec 中找到。

    这是我对从哪里开始的建议:

    1. 了解如何将一系列标识符解析为操作数和运算符。请参阅我在此主题上的回答 When to use parenthesis in Scala infix notation
    2. 记住足够运算符优先级list。就个人而言,我只记得算术的+-*/,字母的优先级最低,而奇怪的 unicode 字母的优先级最高。对于其余部分,我会添加括号,或者只是猜测优先级将按照 DSL 设计者的意图或 Java 中的方式“解决”。
    3. 了解列表的x :: xsxs ::: ys 运算符,因为它们非常流行并且与右侧相关联,因为它们以: 结尾。
    4. 或者,如果您感到好奇,可以粗略查看规范的 6.12 前缀、中缀和后缀操作部分,这样您就会在大脑的某个角落知道有有关具有 = 和前缀运算符的运算符的详细信息。

    最后,最后一句忠告。不要试图学习所有的运算符,不要假设你应该知道所有运算符的含义才能有效地使用语言。除非您通过阅读和记住完整的 API 来学习其他语言。

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多