Kotlin操作符符重載
Kotlin 允許我們爲自己的類型提供預定義的一組操作符的實現。這些操作符具有固定的符號表示
(如 + 或 *)和固定的優先級。爲實現這樣的操作符,我們爲相應的類型(即二元操作符左側的類型和一元操作符的參數類型)提供了一個固定名字的成員函數
或擴展函數。
重載操作符的函數需要用 operator 修飾符標記。
約定
在這裏我們描述爲不同操作符規範操作符重載的約定。
一元操作
表達式
翻譯爲
+a
a.unaryPlus()
-a
a.unaryMinus()
!a
a.not()
這個表是說,當編譯器處理例如表達式 +a 時,它執行以下步驟:
- 確定
a的類型,令其爲T。 - 爲接收者
T查找一個帶有operator修飾符的無參函數unaryPlus(),即成員函數或擴展函數。 - 如果函數不存在或不明確,則導致編譯錯誤。
- 如果函數存在且其返回類型爲
R,那就表達式+a具有類型R。
注意 這些操作以及所有其他操作都針對基本類型做了優化,不會爲它們引入函數調用的開銷。
表達式
翻譯爲
a++
a.inc() + 見下文
a--
a.dec() + 見下文
inc() 和 dec() 函數必須返回一個值,它用於賦值給使用++ 或 -- 操作的變量。它們不應該改變在其上調用 inc() 或 dec() 的對象。
編譯器執行以下步驟來解析後綴形式的操作符,例如 a++:
- 確定
a的類型,令其爲T。 - 查找一個適用於類型爲
T的接收者的、帶有operator修飾符的無參數函數inc()。 - 檢查函數的返回類型是
T的子類型。
計算表達式的步驟是:
- 把
a的初始值存儲到臨時存儲a0中, - 把
a.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 中被棄用。
表達式
翻譯爲
a in b
b.contains(a)
a !in b
!b.contains(a)
對於 in 和 !in,過程是相同的,但是參數的順序是相反的。
{:#in}
表達式
翻譯爲
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)
方括號轉換爲調用帶有適當數量參數的 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)
圓括號轉換爲調用帶有適當數量參數的 invoke。
表達式
翻譯爲
a += b
a.plusAssign(b)
a -= b
a.minusAssign(b)
a *= b
a.timesAssign(b)
a /= b
a.divAssign(b)
a %= b
a.modAssign(b)
{:#assignments}
對於賦值操作,例如 a += b,編譯器執行以下步驟:
- 如果右列的函數可用
- 如果相應的二元函數(即
plusAssign()對應於plus())也可用,那麼報告錯誤(模糊)。 - 確保其返回類型是
Unit,否則報告錯誤。 - 生成
a.plusAssign(b)的代碼
- 如果相應的二元函數(即
- 否則試着生成
a = a + b的代碼(這裏包含類型檢查:a + b的類型必須是a的子類型)。
注意:賦值在 Kotlin 中不是表達式。
{:#Equals}
表達式
翻譯爲
a == b
a?.equals(b) ?: (b === null)
a != b
!(a?.equals(b) ?: (b === null))
注意:=== 和 !==(同一性檢查)不可重載,因此不存在對他們的約定
這個 == 操作符有些特殊:它被翻譯成一個複雜的表達式,用於篩選 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 的調用,這個函數需要返回 Int 值
命名函數的中綴調用
我們可以通過中綴函數的調用 來模擬自定義中綴操作符。