转载

Scala 中置, 前置, 后置操作符

拟此篇以温习 Scala 对方法调用上的一些约定. 标题中说是关于操作符的事, 其实 Scala 像有了访问方法和属性的一致性原则一样, 可以说操作符与方法更是统一的, 或者说只有方法调用. 此处所称的操作符只不过是 Scala 对无参(prrameterless), 或只有一个参数的方法, 和特殊的四个 unary_+ , unary_- , unary_! , unary_~ 方法的便捷的调用约定格式.

一. 中置操作符(对只有一个参数方法的调用约定, a plus b )

case class MyNumber(value: Int) {

def +(that: MyNumber) = MyNumber(this.value + that.value)

}

调用方式

MyNumber(10).+(MyNumber(20))   //标准调用格式 MyNumber(10) + MyNumber(20)    //只有一个参数时, 不用点, 不用括号

第一行是用点语法的标准方法调用格式, Scala 在当方法只有一个参数时, 可以省略点, 以及括号 , 因此可写为上面第二行种的格式. 所以方法 + 就化身为了中置操作符了.

+ 只是一个普通的方法名而已, 因为 Scala 可以用很多符号来定义方法. 所以对于任何的只有一个参数的方法调用可以这么写, 假如 MyNumber 定义了方法

def plus(added: Int) = MyNumber(this.value + added)

应用同样的规则可写成

MyNumber(10) plus 20  //而可不必写成  MyNumber(10).plus(20)

这个约定十分有利于写出 DSL 风格的代码, 例如我们在测试中用 MustMatchers 时这么断言

actualList must have size 10

上面其实就是进行连续了三次是置操作符调用 size, have, 和 must.

除中置操作符外, 另外两种前置与后置操作符又统称为一元操作符, 因为它是不带参数的, 首先来看后置操作符

二. 后置操作符(对于无参数的方法的调用约定, a next )

当函数无参数时, 调用时规则约定其实和只有一个参数时是一样的, 省略点以及括号, 既然一个参数都没有, 所以就只有方法名了. 例子

case class MyNumber(value: Int) {   def -- = MyNumber(this.value -1) }

调用方式

MyNumber(10).--  //这是标准格式 MyNumber(10) --  //无参方法的约定格式

由于前面定义的 -- 是无参方法(Parameterless), 所以调用时不能加括号, MyNumber(10).--() 是错误的. 如果是定义的空参数方法(Empty-Paren), 则既可以 MyNumber(10).--() 也可以写成 MyNumber(10) -- , 还能 MyNumber(10).-- , 但后两者会有警告.

def --() = MyNumber(this.value -1)  //Empty-paren 方法 .... MyNumber(10) --      //Warning: Empty-paren method accessed as parameterless MyNumber(10).--     //Warning: Empty-paren method accessed as parameterless MyNumber(10).--()

所以对于后置操作符, 特别是无副作用时应该定义为不带括号的无参方法, 形如 def -- = ....

后置的调用方式很常见, 如

a toString  //而不用写成 a.toString() 或 a.toString a mkString

三. 前置操作符(+, -, !, ~ 的几个特例方法而已)

Scala 可以实现在操作数前加 + , - , ! , ~ 操作符, 如 -a , 所以它们叫做前置(prefix) 操作符. Scala 的做法是把它们分别映射到方法 unary_+ , unary_- , unary_! , 和 unary_~ . 示例

case class MyNumber(value: Int) {   def unary_+ = MyNumber(this.value + 1) }

调用时写成

MyNumber.unary_+  //标准调用格式, 或 MyNumber unary_+ +MyNumber(10)    //实际就调用了 unary_+ 方法

注意, 前置操作只能映射前面四种操作, 想别的都没有. 比如你是否有冲动在 Scala 中实现出 ++a 呢? Scala 是不支持传统的 ++ 递增操作, 后置的 a++ 我们可以用 def ++ = ... 实现. 对于前置的 ++a 如果尝试写成

def unary_++ = MyNumber(this.value + 1) .... //++MyNumber(10)  //这是无效的, 尝试不会是徒劳的. 只能显式的用下面两种方式调用 MyNumber(10).unary_++ MyNumber(10) unary_++

下面是测试上面三种方式的完整代码

import scala.language.postfixOps  case class MyNumber(value: Int) {   def +(that: MyNumber) = MyNumber(this.value + that.value)   def ++ = MyNumber(this.value + 1) //parameterless   // def -- = MyNumber(this.value - 1) //recommended  def --() = MyNumber(this.value - 1) //Warning: Empty-paren, not recommended for no side-effect method   def unary_- = MyNumber(-this.value) }  object Main extends App {   println("Infix: " + (MyNumber(10) + MyNumber(20))) //recommended  println(MyNumber(10).+(MyNumber(20))) //regular method calling style   println("Postfix1: " + (MyNumber(10) ++)) //recommended  println(MyNumber(10).++) //regular method calling style   // MyNumber(10).++() //Compilation error: Application does not take parameters   println("Postfix2: " + (MyNumber(10) --)) //Warning: Empty-paren method accessed as parameterless  println((MyNumber(10).--)) //Warning: Empty-paren method accessed as parameterless  println(MyNumber(10).--()) //regular method calling style   println("Prefix: " + -MyNumber(10))   println(MyNumber(10).unary_-)  println((MyNumber(10) unary_-)) }

上面代码的输出

Infix: MyNumber(30)

MyNumber(30)

Postfix1: MyNumber(11)

MyNumber(11)

Postfix2: MyNumber(9)

MyNumber(9)

MyNumber(9)

Prefix: MyNumber(-10)

MyNumber(-10)

MyNumber(-10)

原文  http://unmi.cc/scala-infix-prefix-postfix-operators/
正文到此结束
Loading...