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)
}
调用方式
1MyNumber(10).+(MyNumber(20)) //标准调用格式
2MyNumber(10) + MyNumber(20) //只有一个参数时, 不用点, 不用括号第一行是用点语法的标准方法调用格式, Scala 在当方法只有一个参数时, 可以省略点, 以及括号,
因此可写为上面第二行种的格式. 所以方法 + 就化身为了中置操作符了.
+ 只是一个普通的方法名而已, 因为 Scala 可以用很多符号来定义方法. 所以对于任何的只有一个参数的方法调用可以这么写,
假如 MyNumber 定义了方法
1def plus(added: Int) = MyNumber(this.value + added)应用同样的规则可写成
1MyNumber(10) plus 20 //而可不必写成 MyNumber(10).plus(20)这个约定十分有利于写出 DSL 风格的代码, 例如我们在测试中用 MustMatchers 时这么断言
1actualList must have size 10上面其实就是进行连续了三次是置操作符调用 size, have, 和 must.
除中置操作符外, 另外两种前置与后置操作符又统称为一元操作符, 因为它是不带参数的, 首先来看后置操作符
二. 后置操作符(对于无参数的方法的调用约定, a next)
当函数无参数时, 调用时规则约定其实和只有一个参数时是一样的, 省略点以及括号, 既然一个参数都没有, 所以就只有方法名了. 例子
1case class MyNumber(value: Int) {
2 def -- = MyNumber(this.value -1)
3}调用方式
1MyNumber(10).-- //这是标准格式
2MyNumber(10) -- //无参方法的约定格式由于前面定义的 -- 是无参方法(Parameterless), 所以调用时不能加括号, MyNumber(10).--() 是错误的.
如果是定义的空参数方法(Empty-Paren), 则既可以 MyNumber(10).--() 也可以写成 MyNumber(10) --,
还能 MyNumber(10).--, 但后两者会有警告.
1def --() = MyNumber(this.value -1) //Empty-paren 方法
2....
3MyNumber(10) -- //Warning: Empty-paren method accessed as parameterless
4MyNumber(10).-- //Warning: Empty-paren method accessed as parameterless
5MyNumber(10).--()所以对于后置操作符, 特别是无副作用时应该定义为不带括号的无参方法, 形如 def -- = ....
后置的调用方式很常见, 如
1a toString //而不用写成 a.toString() 或 a.toString
2a mkString三. 前置操作符(+, -, !, ~ 的几个特例方法而已)
Scala 可以实现在操作数前加 +, -, !, ~ 操作符, 如 -a,
所以它们叫做前置(prefix) 操作符. Scala 的做法是把它们分别映射到方法 unary_+, unary_-, unary_!,
和 unary_~. 示例
1case class MyNumber(value: Int) {
2 def unary_+ = MyNumber(this.value + 1)
3}调用时写成
1MyNumber.unary_+ //标准调用格式, 或 MyNumber unary_+
2+MyNumber(10) //实际就调用了 unary_+ 方法注意, 前置操作只能映射前面四种操作, 想别的都没有. 比如你是否有冲动在 Scala 中实现出 ++a 呢?
Scala 是不支持传统的 ++ 递增操作, 后置的 a++ 我们可以用 def ++ = ... 实现.
对于前置的 ++a 如果尝试写成
1def unary_++ = MyNumber(this.value + 1)
2....
3//++MyNumber(10) //这是无效的, 尝试不会是徒劳的. 只能显式的用下面两种方式调用
4MyNumber(10).unary_++
5MyNumber(10) unary_++下面是测试上面三种方式的完整代码
1import scala.language.postfixOps
2
3case class MyNumber(value: Int) {
4
5 def +(that: MyNumber) = MyNumber(this.value + that.value)
6
7 def ++ = MyNumber(this.value + 1) //parameterless
8
9 // def -- = MyNumber(this.value - 1) //recommended
10 def --() = MyNumber(this.value - 1) //Warning: Empty-paren, not recommended for no side-effect method
11
12 def unary_- = MyNumber(-this.value)
13}
14
15object Main extends App {
16
17 println("Infix: " + (MyNumber(10) + MyNumber(20))) //recommended
18 println(MyNumber(10).+(MyNumber(20))) //regular method calling style
19
20 println("Postfix1: " + (MyNumber(10) ++)) //recommended
21 println(MyNumber(10).++) //regular method calling style
22
23 // MyNumber(10).++() //Compilation error: Application does not take parameters
24
25 println("Postfix2: " + (MyNumber(10) --)) //Warning: Empty-paren method accessed as parameterless
26 println((MyNumber(10).--)) //Warning: Empty-paren method accessed as parameterless
27 println(MyNumber(10).--()) //regular method calling style
28
29 println("Prefix: " + -MyNumber(10))
30
31 println(MyNumber(10).unary_-)
32 println((MyNumber(10) unary_-))
33}上面代码的输出
Infix: MyNumber(30)永久链接 https://yanbin.blog/scala-infix-prefix-postfix-operators/, 来自 隔叶黄莺 Yanbin's Blog
MyNumber(30)
Postfix1: MyNumber(11)
MyNumber(11)
Postfix2: MyNumber(9)
MyNumber(9)
MyNumber(9)
Prefix: MyNumber(-10)
MyNumber(-10)
MyNumber(-10)
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。