【问题标题】:Scala's "postfix ops"Scala 的“后缀操作”
【发布时间】:2012-10-12 05:59:08
【问题描述】:

我找了半个小时,还是没弄明白。

SIP: Modularizing Language Features 中,有许多功能需要在 Scala 2.10 (import language.feature) 中明确“启用”。 其中有postfixOps,我在任何地方都找不到参考。这个功能到底允许什么?

【问题讨论】:

  • 最后似乎编译器编译尽管产生警告。所以,也许像我这样的人可能会忽略那些烦人的警告。
  • 我担心 2.11 以后的计划是,结果将是编译错误,而不仅仅是警告。据我了解,带有警告的当前状态只是为了“缓解”过渡......
  • 太糟糕了,我仍然不明白为什么postfix ops 与隐含或存在类型等真正强大的东西在同一个桶中。尝试在 SIP 的页面上询问,但没有答案。
  • 将 -language:postfixOps 添加到 scalac 命令行,一切都和以前一样 - 不需要导入,没有警告。在 build.sbt 中,只需将其添加到您的 scalacOptions Seq。
  • 你不应该在现代程序中使用它,不要压制这个警告,我描述了原因。请检查一下。

标签: scala scala-2.10


【解决方案1】:

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

List(1,2,3) tail

而不是

List(1,2,3).tail

在这个无害的示例中,这不是问题,但它可能会导致歧义。这不会编译:

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

而且错误信息不是很有帮助:

    value ::: is not a member of Unit

它尝试根据foreach 调用的结果调用::: 方法,该调用的类型为Unit。这可能不是程序员的本意。为了得到正确的结果,您需要在第一行之后插入一个分号。

【讨论】:

  • 我的上帝...我非常喜欢它,现在我不得不放置愚蠢的import language.postfixOps 或到处使用点。为什么会这样???!!!
  • 实际上这个 SIP 18 是 scala 中第一个真正令人讨厌和有争议的东西。如果我可以想象结构类型和存在,甚至隐式转换在日常代码中不经常使用,但后缀语法......我尽可能在任何地方使用它。
  • 你确定那个关于后缀操作的例子吗?我可以很容易地提供有用的例子。说:List(1,2,3) map { _ + 1 } reverseList(1,2,3).map( _ + 1).reverse 更易读(当然,恕我直言)
  • @KimStebel 与 ;示例产生警告。但没有错误。这只是某种不同类型的混乱。只是因为有人想使用没有通配符代替参数的方法。这几乎不足以解释为什么 postfixOps 是一个坏主意。
  • +1 用于 appender 中的有趣示例。那应该是 scalapuzzler。
【解决方案2】:

有史以来最简单的答案:

从没有参数的方法中删除点是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)

可以在采用higher order function 一个参数的方法中删除点,例如map、filter、count 和安全! 另外,purely functional 方法如 zip。

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)

详细回答为什么

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

1) 后缀运算符 - 实际上是一个不带参数 (a!==a.!) 且不带括号的方法调用。 (被认为不安全且已弃用)

val b1 = MyBool(false) !!!
List(1,2,3) head

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

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

3) 中缀操作符是一个参数的方法,可以在没有点和括号的情况下调用。仅适用于purely functional 方法

val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2

4) 带有一个或多个参数的方法,如果你用参数调用它,它将不带点链接。 def a(), def a(x), def a(x,y) 但是您应该只对使用higher order function 作为参数的方法执行此操作!

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)

警告示例:

警告:有 1 个弃用警告;使用 -deprecation 重新运行 有关详细信息警告:后缀运算符尾部应通过使 隐含值 scala.language.postfixOps 可见。这可以是 通过添加导入子句'import scala.language.postfixOps' 或通过设置编译器选项 -语言:后缀操作。请参阅 Scala 文档以获取值 scala.language.postfixOps 以讨论为什么该功能应该是 明确启用。

【讨论】:

    【解决方案3】:

    它指的是能够调用一个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
    

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

    【讨论】:

    • 正如我的第二个示例所示,它不限于空方法。
    • 我不确定您指的是哪个示例。无论如何,我想如果你想挑剔,这确实也适用于所有参数都有默认值的非空方法。无论如何,我只是在解释官方的 scala 文档(见链接):“正如这段代码的第一行所示,也可以使用 nullary 方法作为后缀运算符”。
    • 不,不需要默认值。我指的是我回答中的示例,特别是val appender:List[Int] => List[Int] = List(1,2,3) ::: 行。 ::: 方法不是 nullary,也没有默认值。
    • 很公平。我已经检查过了,似乎 postfixOps 也包含这种情况,尽管对我来说它们完全不同(您的示例显示如何将myObject.myMethod 默默地视为与myObject.myMethod _ 相同)。
    • +1 表示比答案更吸引人的评论部分。
    猜你喜欢
    • 2016-06-17
    • 2018-02-14
    • 2011-12-10
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多