Scala的"postfix ops"

dmi*_*try 55 scala scala-2.10

我搜索了半个小时,仍然无法弄明白.

SIP:模块化语言功能中,有许多功能需要在Scala 2.10(import language.feature)中明确"启用" .其中有postfixOps,我无法在任何地方找到参考.这个功能究竟允许什么?

Kim*_*bel 58

它允许您在后缀位置使用运算符语法.例如

List(1,2,3) tail
Run Code Online (Sandbox Code Playgroud)

而不是

List(1,2,3).tail
Run Code Online (Sandbox Code Playgroud)

在这个无害的例子中,它不是问题,但它可能导致含糊不清.这不会编译:

val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}
Run Code Online (Sandbox Code Playgroud)

并且错误消息不是很有用:

    value ::: is not a member of Unit
Run Code Online (Sandbox Code Playgroud)

它试图在调用的:::结果上调用该方法foreach,该类型是调用的Unit.这可能不是程序员的意图.要获得正确的结果,您需要在第一行后插入分号.

  • 我的上帝...我非常喜欢它,现在我被迫放置愚蠢的`import language.postfixOps`或在任何地方使用点.为什么这个???!!! (7认同)
  • 你确定那个关于postfix操作的例子吗?我可以很容易地提供有用的示例.说:`List(1,2,3)map {_ + 1} reverse`比`List(1,2,3).map(_ + 1).reverse更具可读性(当然是imho) (4认同)
  • 给appender中有趣的例子+1.那应该是scalapuzzler. (3认同)
  • 实际上,这个SIP 18是scala中第一个真正令人烦恼和争议的东西.如果我可以想象结构类型和存在性,甚至隐式转换在日常代码中不经常使用,但是后缀语法......我尽可能在任何地方使用它. (2认同)
  • @KimStebel随着; 示例产生警告.但没有错误.这只是一种不同类型的混乱.只是因为有人想要在没有通配符的情况下用方法来代替参数.这几乎不足以解释为什么postfixOps是个坏主意. (2认同)

Ale*_*lex 31

有史以来最简单的答案:

从没有参数的方法中删除点是DEPRECATED!

List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)
Run Code Online (Sandbox Code Playgroud)

可以在采用高阶函数的一个参数的方法中删除点,如map,filter,count和安全!此外,纯粹的功能方法,如拉链.

List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) zip List(2,4,6)
Run Code Online (Sandbox Code Playgroud)

为什么要回答

case class MyBool(x: Boolean) {
  def !!! = MyBool(!x) //postfix
  def or(other: MyBool): MyBool = if(x) other else this //infix
  def justMethod0() = this //method with empty parameters
  def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
  override def toString = if(x) "true" else "false"
}
Run Code Online (Sandbox Code Playgroud)

1) Postfix运算符 - 实际上是一个没有参数的方法调用(a!== a.!)而没有括号.(被认为不安全和弃用)

val b1 = MyBool(false) !!!
List(1,2,3) head
Run Code Online (Sandbox Code Playgroud)

2) Postfix运算符是方法,应该结束该行,否则它将被视为中缀.

val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR
Run Code Online (Sandbox Code Playgroud)

3)中缀运算符是具有一个参数的方法,可以在没有点和括号的情况下调用.仅适用于纯功能方法

val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2
Run Code Online (Sandbox Code Playgroud)

4)如果用参数调用,带有一个或多个参数的方法将链无点.def a(),def a(x),def a(x,y)但是你应该只对使用高阶函数作为参数的方法这样做!

val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)
Run Code Online (Sandbox Code Playgroud)

示例警告:

警告:有1个弃用警告; 使用-deprecation重新运行以获取详细信息警告:应通过使隐式值scala.language.postfixOps可见来启用postfix operator tail.这可以通过添加import子句'import scala.language.postfixOps'或通过设置编译器选项-language:postfixOps来实现.有关为何应明确启用该功能的讨论,请参阅Scala文档以获取值scala.language.postfixOps.


Rég*_*les 5

它指的是调用nullary(没有arg列表或空arg列表)方法作为后缀运算符的能力:

举例:

case class MyBool(value: Boolean) {
    def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated
Run Code Online (Sandbox Code Playgroud)

见:http://www.scala-lang.org/node/118

  • 很公平.我已经检查了,看起来postfixOps似乎也包含了这个案例,即使对我来说它们也完全不同(你的例子显示了`myObject.myMethod`可以像`myObject.myMethod _`一样被静默处理). (2认同)