在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)_
(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
mkString显然返回一个字符串,在其上(通过隐式转换AFAIK)我可以使用map函数。
为什么这个特殊情况需要括号?是否有关于何时以及为何需要它的一般指导原则?
答案 0 :(得分:35)
这是我在阅读规范后为自己整理的内容:
a.m(b)
可以写成a m b
。a.m
可以写成a m
。例如a.##(b)
可以写成a ## b
而a.!
可以写a!
foo bar baz
表示foo.bar(baz)
,而foo bar baz bam
表示(foo.bar(baz)).bam
,foo bar baz bam bim
表示(foo.bar(baz)).bam(bim)
。 a.m.m
有效但a m m
不会像{{1}那样解析}}。由于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
所有优先事项都在键入和其他阶段之前发生,所以尽管fromFile(file).mkString map { }
没有意义list mkString map function
,但这就是它的解析方式。
答案 1 :(得分:5)
Scala reference提及(6.12.3:Pre fi x,In fi x和Post fi x Operations)
在固定操作
t0 op1 t1 op2 . . .opn tn
中的连续类型序列中,所有操作符op1, . . . , opn
必须具有相同的关联性。
如果它们都是左关联的,则序列被解释为(. . . (t0 op1 t1) op2 . . .) opn tn
。
在您的情况下,“map
”不是运算符“mkstring
”的术语,因此您需要进行分组(使用括号“fromFile(file) mkString
”)
实际上,Matt R评论:
这不是一个真正的关联性问题,更多的是“ Post fi x运算符的优先级始终低于运算符。例如,
e1 op1 e2 op2
总是等于(e1 op1 e2) op2
”。 (也来自6.12.3)
huynhjl的answer(upvoted)提供了更多详细信息,而Mark Bush的answer(也是upvoted)指向“A Tour of Scala: Operators”来说明“任何采用单个参数的方法都可以用作中缀运算符”。
答案 2 :(得分:4)
这是一个简单的规则:从未使用过postfix运算符。如果这样做,请将整个表达式以括号内的postfix运算符结尾。
实际上,从Scala 2.10.0开始,这样做会默认生成警告。
为了更好地衡量,您可能希望将后缀运算符移出,并使用点表示法。例如:
(fromFile(file)).mkString map caesar(k)_
或者,更简单地说,
fromFile(file).mkString map caesar(k)_
另一方面,请注意可以提供空括号以将其转换为中缀的方法:
fromFile(file) mkString () map caesar(k)_
答案 3 :(得分:2)
规范并不清楚,但我的经验和实验表明,Scala编译器总是尝试使用中缀表示法作为中缀运算符来处理方法调用。即使您使用mkString是后缀,编译器也会尝试将其解释为中缀,因此尝试将“map”解释为其参数。 postfix运算符的所有用法必须紧跟一个表达式终止符,或者与“dot”表示法一起使用,编译器才能看到它。
你可以在A Tour of Scala: Operators中得到一些暗示(虽然没有拼写出来)。