探索Scala(1)-- 運算子過載
Scala語言運算子過載完全是語法層面的小把戲,本文記錄我對Scala語言運算子過載的一些理解。
方法呼叫語法糖
呼叫方法時,Scala允許省略點號和圓括號,如下面程式碼所示:
把運算子對映成單詞
對於Scala來說,運算子和普通的方法沒什麼兩樣。比如下面這個類就過載了加號和減號:
我們可以這樣使用MyInt:
var myInt = new MyInt(1)
myInt = myInt + 1
用javap或者classpy分析一下scalac編譯之後的類可以知道,+實際上被編譯成了$plus()方法,-被編譯成了$minus()方法。也就是說,下面三行程式碼完全等價:
myInt = myInt + 1 myInt = myInt.+(1) myInt = myInt.$plus(1)
多符號運算子
多符號運算子無非就是單個運算子的簡單組合而已,給MyInt新增一個多符號運算子+++,如下所示:
那麼可以這樣使用+++:
var myInt = new MyInt(1)
myInt = myInt +++ 1
反編譯MyInt.class可以知道,scalac把+++運算子編譯成了$plus$plus$plus()方法。
op=語法糖
如果一個類過載了op運算子,但是沒有過載op=,那麼Scala編譯器會把x op= y替換為x = x op y,也就是x = x.op(y),程式碼如下所示:
var myInt = new MyInt(1) myInt += 1 // myInt = myInt + 1
繫結規則
如果運算子以冒號結束,那麼運算子會繫結(bind)到右邊的運算元,也就是說,x op: y等價於y.op:(x)。我們給MyInt增加一個+:運算子,如下所示:
那麼可以這樣使用+:運算子:
var myInt = new MyInt(1)
println(1 +: myInt) // myInt.+:(1)
一元運算子
只有四種運算子可以被定義為一元(Unary)運算子,它們是:+、-、!、~,如下面程式碼所示:
下面是示例程式碼:
val myInt = new MyInt(1) println(-myInt) // -1 println(!myInt) // 99 println(~myInt)
圓括號語法糖
如果一個類定義了apply()方法,那麼Scala提供了語法糖,讓該類的例項看起來像是函式(可以直接呼叫)或陣列(可以按下標訪問元素)。如果類定義了update()方法,那麼就可以像陣列那樣按下標賦值。比如下面的Pair類:
可以像下面這樣使用Pair類:
val xy = new Pair(Array(3, 7))
println(xy(0)) // 3
println(xy(1)) // 7
xy(0) = 11
xy(1) = 18
println(xy(0)) // 11
println(xy(1)) // 18
運算子對照表
下面是我整理出來的運算子和Scala內部名稱的對照表:
+ | $plus |
- | $minus |
* | $times |
/ | $div |
% | $percent |
& | $amp |
| | $bar |
^ | $up |
~ | $tilde |
> | $greater |
< | $less |
! | $bang |
? | $qmark |
= | $eq |
: | $colon |
@ | $at |
# | $hash |
\ | $bslash |
$ | $ |
參考資料
http://www.scala-lang.org/documentation/
http://stackoverflow.com/questions/7888944/scala-punctuation-aka-symbols-and-operators
《Programming in Scala》第二版
《Scala for the Impatient》