何时在Scala中缀表示法中使用括号

Fel*_*lix 15 dictionary functional-programming scala infix-notation parentheses

在Scala中编程时,我会做越来越多的功能.但是,使用中缀表示法时,很难判断何时需要括号,何时不需要.

例如下面的代码:

def caesar(k:Int)(c:Char) = c match {
    case c if c isLower => ('a'+((c-'a'+k)%26)).toChar
    case c if c isUpper => ('A'+((c-'A'+k)%26)).toChar
    case _ => c
}

def encrypt(file:String,k:Int) = (fromFile(file) mkString) map caesar(k)_
Run Code Online (Sandbox Code Playgroud)

(fromFile(file)mkString)需要括号才能编译.删除后,我收到以下错误:

Caesar.scala:24: error: not found: value map
    def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
                                                                 ^
one error found
Run Code Online (Sandbox Code Playgroud)

mkString显然返回一个字符串,在其上(通过隐式转换AFAIK)我可以使用map函数.

为什么这个特殊情况需要括号?关于何时以及为何需要它,是否有一般指导原则?

huy*_*hjl 35

这是我在阅读规范后为自己整理的内容:

  • 任何采用单个参数的方法都可以用作中缀运算符:a.m(b)可以编写a m b.
  • 任何不需要参数的方法都可以用作后缀运算符:a.m可以编写a m.

例如a.##(b)可以写a ## b,a.!可以写a!

  • Postfix的运营商比中缀运算符的优先级低,因此foo bar baz意味着foo.bar(baz)尽管foo bar baz bam手段(foo.bar(baz)).bamfoo bar baz bam bim方式(foo.bar(baz)).bam(bim).
  • 也给出了参数方法对象的一个,a.m.m是有效的,但a m m不是因为这将作为解析exp1 op exp2.

因为有一个版本mkString需要一个参数,所以它将被视为中缀操作符fromFile(file) mkString map caesar(k)_.还有一个版本mkString没有参数,可以用作后缀运算符:

scala> List(1,2) mkString
res1: String = 12

scala> List(1,2) mkString "a"
res2: String = 1a2
Run Code Online (Sandbox Code Playgroud)

有时通过在正确的位置添加点,您可以获得所需的优先级,例如 fromFile(file).mkString map { }

所有优先事项都是在打字和其他阶段之前发生的,所以即使list mkString map function没有意义list.mkString(map).function,这也就是解析它的方式.


Von*_*onC 5

斯卡拉参考提到(6.12.3:???前X中,x和邮政X操作)

在一系列连续类型的inx操作中t0 op1 t1 op2 . . .opn tn,所有运算符op1, . . . , opn必须具有相同的关联性。
如果它们都是左关联的,则序列解释为(. . . (t0 op1 t1) op2 . . .) opn tn

在您的情况下,“ map”不是运算符“ mkstring” 的术语,因此您需要分组(括号中用“ fromFile(file) mkString” 括起来)


实际上,Matt R评论:

这并不是一个真正的关联性问题,更多的是,“ Post?x运算符的优先级总是比in?x运算符的优先级低。例如,Eg e1 op1 e2 op2始终等于(e1 op1 e2) op2”。(也来自6.12.3)

huynhjl答案(被提议)提供了更多细节,Mark Bush答案(也被提议)指向“ Scala之路:运算​​符 ”以说明“任何采用单个参数的方法都可以用作中缀运算符” 。