何时在 Scala 中缀表示法中使用括号
在使用 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)我可以使用映射函数。
为什么这个特殊情况需要括号?是否有关于何时以及为何需要它的一般准则?
When programming in Scala, I do more and more functional stuff. However, when using infix notation it is hard to tell when you need parenthesis and when you don't.
For example the following piece of code:
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)_
The (fromFile(file) mkString) needs parenthesis in order to compile. When removed I get the following error:
Caesar.scala:24: error: not found: value map
def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
^
one error found
mkString obviously returns a string on which (by implicit conversion AFAIK)I can use the map function.
Why does this particular case needs parentheses? Is there a general guideline on when and why you need it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是我在阅读规范后为自己整理的:
am(b)
可以写成am b
。am
可以写成a m
。例如
a.##(b)
可以写成a ## b
,a.!
可以写成a!< /code>
foo bar baz
表示foo.bar(baz)
而foo bar baz bam
表示(foo.bar(baz)).bam
,而foo bar baz bam bim
表示(foo.bar(baz))。 bam(bim)
。amm
是有效的,但am m
并不像它解析的那样作为exp1 op exp2
。由于
mkString
的一个版本采用单个参数,因此在fromFile(file) mkString map caesar(k)_
中它将被视为中缀运算符。还有一个不带参数的 mkString 版本,可以用作后缀运算符:有时通过在正确的位置添加点,您可以获得所需的优先级,例如 fromFile( file).mkString map { }
并且所有优先级都发生在输入和其他阶段之前,因此即使
list mkString map function
与list.mkString(map) 一样没有任何意义.function
,这就是它的解析方式。This is what I put together for myself after reading the spec:
a.m(b)
can be writtena m b
.a.m
can be writtena m
.For instance
a.##(b)
can be writtena ## b
anda.!
can be writtena!
foo bar baz
meansfoo.bar(baz)
whilefoo bar baz bam
means(foo.bar(baz)).bam
andfoo bar baz bam bim
means(foo.bar(baz)).bam(bim)
.a.m.m
is valid buta m m
is not as it would parse asexp1 op exp2
.Because there is a version of
mkString
that takes a single parameter it will be seen as an infix opertor infromFile(file) mkString map caesar(k)_
. There is also a version ofmkString
that takes no parameter which can be used a as postfix operator:Sometime by adding dot in the right location, you can get the precedence you need, e.g.
fromFile(file).mkString map { }
And all that precedence thing happens before typing and other phases, so even though
list mkString map function
makes no sense aslist.mkString(map).function
, this is how it will be parsed.Scala 参考 提到(6.12.3:前缀、中缀和后修复操作)
在您的情况下,“
map
”不是运算符“mkstring
”的术语,因此您需要分组(在“fromFile(file)”周围使用括号mkString
')实际上,Matt R 评论:
huynhjl 的 答案(已投票)提供了更多详细信息,并且 马克·布什的答案(也已投票)指向“Scala 之旅:运算符< /a>”来说明“任何采用单个参数的方法都可以用作中缀运算符”。
The Scala reference mentions (6.12.3: Prefix, Infix, and Postfix Operations)
In your case, '
map
' isn't a term for the operator 'mkstring
', so you need grouping (with the parenthesis around 'fromFile(file) mkString
')Actually, Matt R comments:
huynhjl's answer (upvoted) gives more details, and Mark Bush's answer (also upvoted) point to "A Tour of Scala: Operators" to illustrate that "Any method which takes a single parameter can be used as an infix operator".
这是一个简单的规则:永远不要使用后缀运算符。如果这样做,请将以后缀运算符结尾的整个表达式放在括号内。
事实上,从 Scala 2.10.0 开始,这样做将默认生成警告。
为了更好地衡量,您可能需要将后缀运算符移出,并使用点表示法。例如:
或者,更简单的是,
另一方面,请注意可以提供空括号以将它们转换为中缀的方法:
Here's a simple rule: never used postfix operators. If you do, put the whole expression ending with the postfix operator inside parenthesis.
In fact, starting with Scala 2.10.0, doing that will generate a warning by default.
For good measure, you might want to move the postfix operator out, and use dot notation for it. For example:
Or, even more simply,
On the other hand, pay attention to the methods where you can supply an empty parenthesis to turn them into infix:
规范没有明确说明,但我的经验和实验表明,Scala 编译器将始终尝试将使用中缀表示法的方法调用视为中缀运算符。即使您使用的 mkString 是后缀,编译器也会尝试将其解释为中缀,因此尝试将“map”解释为其参数。后缀运算符的所有使用都必须紧跟表达式终止符,或者与“点”符号一起使用,以便编译器将其视为这样。
您可以在Scala 之旅:运算符。
The spec doesn't make it clear, but my experience and experimentation has shown that the Scala compiler will always try to treat method calls using infix notation as infix operators. Even though your use of mkString is postfix, the compiler tries to interpret it as infix and so is trying to interpret "map" as its argument. All uses of postfix operators must either be immediately followed by an expression terminator or be used with "dot" notation for the compiler to see it as such.
You can get a hint of this (although it's not spelled out) in A Tour of Scala: Operators.