https://www.kotlincn.net/docs/reference/operator-overloading.html
Kotlin 允許我們?yōu)樽约旱念愋吞峁╊A定義的一組操作符的實現(xiàn)。這些操作符具有固定的符號表示 (如 + 或 *)和固定的優(yōu)先級。為實現(xiàn)這樣的操作符,我們?yōu)橄鄳念愋停炊僮鞣髠鹊念愋秃鸵辉僮鞣膮?shù)類型)提供了一個固定名字的成員函數(shù)或擴展函數(shù)。 重載操作符的函數(shù)需要用 operator 修飾符標記。
另外,我們描述為不同操作符規(guī)范操作符重載的約定。
一元操作
一元前綴操作符
| 表達式 | 翻譯為 |
|---|---|
+a |
a.unaryPlus() |
-a |
a.unaryMinus() |
!a |
a.not() |
這個表是說,當編譯器處理例如表達式 +a 時,它執(zhí)行以下步驟:
- 確定
a的類型,令其為T; - 為接收者
T查找一個帶有operator修飾符的無參函數(shù)unaryPlus(),即成員函數(shù)或擴展函數(shù); - 如果函數(shù)不存在或不明確,則導致編譯錯誤;
- 如果函數(shù)存在且其返回類型為
R,那就表達式+a具有類型R;
注意 這些操作以及所有其他操作都針對基本類型做了優(yōu)化,不會為它們引入函數(shù)調用的開銷。
以下是如何重載一元減運算符的示例:
data class Point(val x: Int, val y: Int)
operator fun Point.unaryMinus() = Point(-x, -y)
val point = Point(10, 20)
fun main() {
println(-point) // 輸出“Point(x=-10, y=-20)”
}
Target platform: JVMRunning on kotlin v. 1.7.10
遞增與遞減
| 表達式 | 翻譯為 |
|---|---|
a++ |
a.inc() + 見下文 |
a-- |
a.dec() + 見下文 |
inc() 和 dec() 函數(shù)必須返回一個值,它用于賦值給使用 ++ 或 -- 操作的變量。它們不應該改變在其上調用 inc() 或 dec() 的對象。
編譯器執(zhí)行以下步驟來解析后綴形式的操作符,例如 a++:
- 確定
a的類型,令其為T; - 查找一個適用于類型為
T的接收者的、帶有operator修飾符的無參數(shù)函數(shù)inc(); - 檢測函數(shù)的返回類型是
T的子類型。
計算表達式的步驟是:
- 把
a的初始值存儲到臨時存儲a0中; - 把
a0.inc()結果賦值給a; - 把
a0作為表達式的結果返回。
對于 a--,步驟是完全類似的。
對于前綴形式 ++a 和 --a 以相同方式解析,其步驟是:
- 把
a.inc()結果賦值給a; - 把
a的新值作為表達式結果返回。
二元操作
算術運算符
| 表達式 | 翻譯為 |
|---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.times(b) |
a / b |
a.div(b) |
a % b |
a.rem(b)、 a.mod(b) (已棄用) |
a..b |
a.rangeTo(b) |
對于此表中的操作,編譯器只是解析成翻譯為列中的表達式。
請注意,自 Kotlin 1.1 起支持 rem 運算符。Kotlin 1.0 使用 mod 運算符,它在 Kotlin 1.1 中被棄用。
示例
下面是一個從給定值起始的 Counter 類的示例,它可以使用重載的 + 運算符來增加計數(shù):
data class Counter(val dayIndex: Int) {
operator fun plus(increment: Int): Counter {
return Counter(dayIndex + increment)
}
}
“In”操作符
| 表達式 | 翻譯為 |
|---|---|
a in b |
b.contains(a) |
a !in b |
!b.contains(a) |
對于 in 和 !in,過程是相同的,但是參數(shù)的順序是相反的。
索引訪問操作符
| 表達式 | 翻譯為 |
|---|---|
a[i] |
a.get(i) |
a[i, j] |
a.get(i, j) |
a[i_1, ……, i_n] |
a.get(i_1, ……, i_n) |
a[i] = b |
a.set(i, b) |
a[i, j] = b |
a.set(i, j, b) |
a[i_1, ……, i_n] = b |
a.set(i_1, ……, i_n, b) |
方括號轉換為調用帶有適當數(shù)量參數(shù)的 get 和 set。
調用操作符
| 表達式 | 翻譯為 |
|---|---|
a() |
a.invoke() |
a(i) |
a.invoke(i) |
a(i, j) |
a.invoke(i, j) |
a(i_1, ……, i_n) |
a.invoke(i_1, ……, i_n) |
圓括號轉換為調用帶有適當數(shù)量參數(shù)的 invoke。
廣義賦值
| 表達式 | 翻譯為 |
|---|---|
a += b |
a.plusAssign(b) |
a -= b |
a.minusAssign(b) |
a *= b |
a.timesAssign(b) |
a /= b |
a.divAssign(b) |
a %= b |
a.remAssign(b), a.modAssign(b)(已棄用) |
對于賦值操作,例如 a += b,編譯器執(zhí)行以下步驟:
- 如果右列的函數(shù)可用
- 如果相應的二元函數(shù)(即
plusAssign()對應于plus())也可用,那么報告錯誤(模糊), - 確保其返回類型是
Unit,否則報告錯誤, - 生成
a.plusAssign(b)的代碼;
- 如果相應的二元函數(shù)(即
- 否則試著生成
a = a + b的代碼(這里包含類型檢測:a + b的類型必須是a的子類型)。
注意:賦值在 Kotlin 中不是表達式。
相等與不等操作符
| 表達式 | 翻譯為 |
|---|---|
a == b |
a?.equals(b) ?: (b === null) |
a != b |
!(a?.equals(b) ?: (b === null)) |
這些操作符只使用函數(shù) equals(other: Any?): Boolean,可以覆蓋它來提供自定義的相等性檢測實現(xiàn)。不會調用任何其他同名函數(shù)(如 equals(other: Foo))。
注意:=== 和 !==(同一性檢測)不可重載,因此不存在對他們的約定。
這個 == 操作符有些特殊:它被翻譯成一個復雜的表達式,用于篩選 null 值。 null == null 總是 true,對于非空的 x,x == null 總是 false 而不會調用 x.equals()。
比較操作符
| 表達式 | 翻譯為 |
|---|---|
a > b |
a.compareTo(b) > 0 |
a < b |
a.compareTo(b) < 0 |
a >= b |
a.compareTo(b) >= 0 |
a <= b |
a.compareTo(b) <= 0 |
所有的比較都轉換為對 compareTo 的調用,這個函數(shù)需要返回 Int 值
屬性委托操作符
provideDelegate、 getValue 以及 setValue 操作符函數(shù)已在委托屬性中描述。
具名函數(shù)的中綴調用
我們可以通過中綴函數(shù)的調用 來模擬自定義中綴操作符。