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)

方括號轉換爲調用帶有適當數量參數的 getset

表達式

翻譯爲

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,對於非空的 xx == 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

命名函數的中綴調用

我們可以通過中綴函數的調用 來模擬自定義中綴操作符。