java里面不支持的operator overloading(操作符重载)又在scala里面被支持了。严格意义上来说scala里面没有operator这个概念,operator只不过是普通函数而已。不过不管怎样,终于又可以这样写代码了,

class Foo(val v: Int) {
 def +(n: Int) = v + n
}
val foo = new Foo(1)
foo + 2  // 3
foo.+(2) // 3

java中唯一被重载的操作符是“+”,用于字符串拼接。在进行字符串操作时很容易发现“+”的好处,所以本质上来说操作符重载是有其相当正面作用的。不过既然可以重载,就可能会看到类似这种很难理解的代码,

class Foo {
 def ^-^(v: String) = "^-^ " + v
}
val foo = new Foo()
foo ^-^ "foobar" // ^-^ foobar

个人开发的话只要自己能看明白就好了,团队开发的话就必须进行相应的约定了。这种约定操作起来并不困难,就和普通的编码规范一样。java剥夺了操作符重载的能力,scala恢复了这一功能,让开发人员重新获得了决定权。负责任的开发者还是不会允许乱七八糟的符号定义的..

在操作符重载上scala没有过多限制,scala对函数名称的字符限制很宽松,想进行操作符重载直接创建相应的名称的函数就可以了。操作符主要还是分为一元、二元操作符。scala对一元操作符的定义有限制,只有+、-、~、!能被用于一元操作符,在定义函数时需加上前缀unary_,

class Foo(val v: Int) {
 def unary_+ = 1 * v
 def unary_- = -1 * v
 def unary_! = {if (v != 0) false else true}
 def ! = (1 to v).reduce(_ * _)
}
val foo = new Foo(5)
+foo / 5
-foo / -5
!foo / false
foo! / 120

像在c++那样,操作符重载需要解决下面这个问题,

class Foo(val v: Int) {
 def +(n: Int) = n + v
}
val foo = new Foo(1)
foo + 1 // 2
1 + foo // error

上述代码中foo + 1运行正确,因为这等同于foo.+(1);1 + foo运行错误,foo类型不符合整数上定义的+操作。对此scala中可以通过implicit conversion(隐式转化)来解决,

implicit def intToFoo(n: Int): Foo = {
 new Foo(n)
}
class Foo(val v: Int) {
 def +(n: Int) = n + v
 def +(f: Foo) = v + f.v
}
val foo = new Foo(1)
foo + 1 // 2
1 + foo // 2

implicit conversion会默默的将1转化成Foo类型,再进行相应的函数调用。implicit的使用需要小心注意,因为具体转化细节在阅读代码时容易忽略掉。

在scala中进行函数调用时还需要注意究竟哪个是调用方哪个是参数,如,

class Foo(val v: Int) {
 def +(n: Int) = v + n
 def +:(n: Int) = v + n
}
val foo = new Foo(1)
foo + 1  // 2
1 +: foo // 2

上述代码中的1 +: foo这句其实是foo.+:(1),而不是1.+:(foo)。如果操作符后面跟着“:”,则在符号前的才是参数,比如scala中foldLeft操作/:。很不明白为什么要提供这个特性,不清楚这东西应当用在何处..