我已经搜索了半个小时,仍然无法弄清楚。
在SIP: 模块化语言功能中,有许多功能需要在Scala 2.10中显式“启用”(import language.feature
)。
其中有一个叫做postfixOps
的功能,但我无法在任何地方找到相关引用。这个功能确切地允许什么?
我已经搜索了半个小时,仍然无法弄清楚。
在SIP: 模块化语言功能中,有许多功能需要在Scala 2.10中显式“启用”(import language.feature
)。
其中有一个叫做postfixOps
的功能,但我无法在任何地方找到相关引用。这个功能确切地允许什么?
它允许您在后缀位置使用运算符语法。例如:
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
,要么到处使用点号。为什么会这样?!! - dmitryList(1,2,3) map { _ + 1 } reverse
比 List(1,2,3).map( _ + 1).reverse
更易读(当然这只是我的想法)。 - dmitry最简单的回答:
在没有参数的方法中省略点号是不推荐使用的!
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)
对于只有一个 高阶函数 参数的方法,比如 map、filter、count,可以省略参数外的圆点,这样做也是安全的!同时,像 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) 中缀运算符是一种只有一个参数的方法,可以在没有句点和括号的情况下被调用。仅适用于纯函数式方法。
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)。但是你只应该对使用高阶函数作为参数的方法进行此操作!
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)
样例警告:
警告:存在一个过时的警告;使用-deprecation重新运行程序可以查看详情。 警告:后缀操作符 tail 应该通过使隐式值 scala.language.postfixOps 可见来启用。您可以通过添加“import scala.language.postfixOps”导入语句或设置编译器选项 -language:postfixOps 来实现此目标。请参阅Scala文档中关于值scala.language.postfixOps的讨论,了解为什么应该明确启用该特性。
它指的是能够将一个无参方法(不带参数列表或空参数列表)作为后缀运算符调用的能力:
例如:
case class MyBool(value: Boolean) {
def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated
val appender:List[Int] => List[Int] = List(1,2,3) :::
这一行。:::
方法不是无参数的,也没有默认值。 - Kim StebelmyObject.myMethod
可以被默默地视为myObject.myMethod _
)。 - Régis Jean-Gilles