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

发布于 2024-10-31 04:08:06 字数 740 浏览 0 评论 0原文

在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

护你周全 2024-11-07 04:08:07

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

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

例如a.##(b)可以写成a ## ba.!可以写成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)
  • 另外,给定对象 a 的无参数方法 mamm 是有效的,但 am 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

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

并且所有优先级都发生在输入和其他阶段之前,因此即使 list mkString map functionlist.mkString(map) 一样没有任何意义.function,这就是它的解析方式。

This is what I put together for myself after reading the spec:

  • Any method which takes a single parameter can be used as an infix operator: a.m(b) can be written a m b.
  • Any method which does not require a parameter can be used as a postfix operator: a.m can be written a m.

For instance a.##(b) can be written a ## b and a.! can be written a!

  • Postfix operators have lower precedence than infix operators, so foo bar baz means foo.bar(baz) while foo bar baz bam means (foo.bar(baz)).bam and foo bar baz bam bim means (foo.bar(baz)).bam(bim).
  • Also given a parameterless method m of object a, a.m.m is valid but a m m is not as it would parse as exp1 op exp2.

Because there is a version of mkString that takes a single parameter it will be seen as an infix opertor in fromFile(file) mkString map caesar(k)_. There is also a version of mkString that takes no parameter which can be used a as postfix operator:

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

scala> List(1,2) mkString "a"
res2: String = 1a2

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 as list.mkString(map).function, this is how it will be parsed.

何必那么矫情 2024-11-07 04:08:07

Scala 参考 提到(6.12.3:前缀、中缀和后修复操作)

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

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


实际上,Matt R 评论:

这并不是真正的结合性问题,更多的是“后缀运算符的优先级始终低于中缀运算符。例如 e1 op1 e2 op2 始终等于 ( e1 op1 e2) op2"。 (同样来自 6.12.3)

huynhjl答案(已投票)提供了更多详细信息,并且 马克·布什答案(也已投票)指向“Scala 之旅:运算符< /a>”来说明“任何采用单个参数的方法都可以用作中缀运算符”。

The Scala reference mentions (6.12.3: Prefix, Infix, and Postfix Operations)

In a sequence of consecutive type infix operations t0 op1 t1 op2 . . .opn tn, all operators op1, . . . , opn must have the same associativity.
If they are all left-associative, the sequence is interpreted as (. . . (t0 op1 t1) op2 . . .) opn tn.

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:

It's not really an associativity issue, more that "Postfix operators always have lower precedence than infix operators. E.g. e1 op1 e2 op2 is always equivalent to (e1 op1 e2) op2". (Also from 6.12.3)

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".

千年*琉璃梦 2024-11-07 04:08:07

这是一个简单的规则:永远不要使用后缀运算符。如果这样做,请将以后缀运算符结尾的整个表达式放在括号内。

事实上,从 Scala 2.10.0 开始,这样做将默认生成警告。

为了更好地衡量,您可能需要将后缀运算符移出,并使用点表示法。例如:

(fromFile(file)).mkString map caesar(k)_

或者,更简单的是,

fromFile(file).mkString map caesar(k)_

另一方面,请注意可以提供空括号以将它们转换为中缀的方法:

fromFile(file) mkString () map caesar(k)_

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:

(fromFile(file)).mkString map caesar(k)_

Or, even more simply,

fromFile(file).mkString map caesar(k)_

On the other hand, pay attention to the methods where you can supply an empty parenthesis to turn them into infix:

fromFile(file) mkString () map caesar(k)_
江挽川 2024-11-07 04:08:07

规范没有明确说明,但我的经验和实验表明,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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文