【kotlin】操作符重載

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ù)的 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)

圓括號轉換為調用帶有適當數(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) 的代碼;
  • 否則試著生成 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

屬性委托操作符

provideDelegategetValue 以及 setValue 操作符函數(shù)已在委托屬性中描述。

具名函數(shù)的中綴調用

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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容