Kotlin 之操作符重載
參考:
- kotlin in action
- kotlin 官方參考文檔
運算符重載
Kotlin允許我們為自己的類型提供預定義的一組操作符實現(這些操作符都對應的成員函數或擴展函數),他們是一一對應的,如:
(+ 對應 plus);
通過這個操作符,如+,可調用plus 方法;
如:在Kotlin中,為類定義了一個plus
方法,按照約定,可以在該類型實例上通過+
運算符,來實現 調用 plus方法;
重載操作符的函數需要用 operator
關鍵字標記;
從以下類開始
data class Pointer(val x:Int, val y:Int)
1. 重載算術運算符
在Kotlin中,使用約定最直接的就是算術運算符了;對比java
,java只能用在基本類型中;
1.1 重載二元運算符
用於操作符重載的所有函數使用
operator
關鍵字標記,這里不是碰巧的;
a. 重載成員函數
為Pointer
類添加 +
號操作,把2個點的x,y
加在一起
```
operator fun plus(other:Pointer) :Pointer { return Pointer(x + other.x, y + other.y) } ```
b. 重載擴展函數
這就厲害了,可給第三方庫的一些類,實現重載操作符了;
重要說明
Kotlin限定了只能重載哪些操作符,以及在類中定義的名字,這樣就避免了操作符的濫用;
可重載的二元算術運算符
``` 表達式 函數 a*b times a/b div a%b mod a+b plus a-b minus ```
c. 優先級的概念
與標准數字類型的運算符有着相同的優先級;
d.其他說明
定義運算符時,2個運算數,可以是不同的類型,比如如下:
```
operator fun div(scale:Float):Pointer { return Pointer((x * scale).toInt(), (y * scale).toInt()) } ```
Kotlin運算符不支持
交換性
(比如:乘法的交換律)
比如:1.5 * pointer
與 pointer * 1.5
是不一樣的;
同於運算數,運算符函數的返回類型也可以不一樣,如:
``` operator fun Char.times(count:Int):String { return toString().repeat(count) } ```
同於普通函數,
operator
方法允許重載(形參參數類型不一樣);
1.2 位運算
Kotlin中,沒有為標准數字類型,定義任何位運算符;他們使用中綴
調用語法的常規函數;
比如:xor,and,or 等;
1.3 重載復合賦值運算符
+=, -=
這種被稱為復合賦值運算符
,kotlin也是支持的;
在一些情況下,定義+=
運算可以修改變量所引用的對象,但不會重新分配引用,用於可變集合;
``` val nums = ArrayList<Int>() nums += 58 // 類似調用add方法 println(nums) ```
Kotlin為標准可變集合定義plusAssign
函數(minusAssign,timesAssign)等,可以看下其源代碼;
1.4 重載一元運算符
-a, +a
這種一元運算符,與上面的類似,函數名不能隨意取
可重載的一元算術運算符
``` 表達式 函數 +a unaryPlus -a unaryMinus !a not ++a,a++ inc --a,a-- dec ```
例子:
```
operator fun unaryMinus() = Pointer(-x, -y) // inc dec 編譯器支持 ++a 與 a++ operator fun BigDecimal.inc() = this + BigDecimal.ONE fun main(args: Array<String>) { var n = BigDecimal.ZERO println(n++) // 0 println(++n) // 2 } ```
2. 重載比較運算符
類似於算術運算符,在Kotlin中,可以對任何對象使用比較運算符(==、!=、 >、<)
等,可以不用像Java那種調用equals,compareTo
函數;
2.1 等號運算符 ==
Kotlin的約定原則之一是:使用==
會轉換成equals
方法調用;但== 與 !=
更安全,會自動檢測是否為 null,如果不為null,才進行判斷;
即:a == b ===> a?.equals(b) ?: (b==null)
例子
``` val p = Pointer(1, 2) val p2 = Pointer(1, 2) println(p == p2) ```
equals
不需要 operator
,因為在Any里面標記過了;
2.2 恆等運算符 ===
恆等運算符等價於Java中的 ==
運算符:檢查2個參數的是否是同一個對象的引用(基本類型判斷值是否相同)
===
不能被重載
2.3 排序運算符 compareTo
Java中,如果對象需要比較,得使用Comparable
接口,不支持 > <
這種,
Kotlin中,可以使用> <
這種符號了, (<,>, <= ,>=)
會轉換成 compareTo
約定調用;
即:a >= b =====> a.compareTo(b) >= 0
例子
```
class Person(val firstName: String, val lastName: String) : Comparable<Person> { override fun compareTo(other: Person): Int { // 先姓,再名 return compareValuesBy(this, other, Person::lastName, Person::firstName) } } ```
在Kotlin中,可以直接使用java中實現Comparable
接口的類,采用更加簡潔的運算符語法;
如:println("abc" < "bac")
3. 集合與區間的約定
處理集合最常見的一些操作,是通過下標來獲取和設置元素,還有就是檢查了;
這些kotlin中也是支持運算符操作的;
獲取 a[1]
(下標操作符),可使用in
運算符來檢查元素是否在集合或區間內;
3.1 通過下標來訪問元素:[] get與set
下標運算符是一個約定,會轉換成對應的 get 或 set方法的調用,比如:map
例子
get方法並用 operator
標記;
```
operator fun Pointer.get(i: Int): Int { return when (i) { 0 -> x 1 -> y else -> throw IndexOutOfBoundsException("Invalid params: $i") } } ```
這個get方法,參數可以是任意類型,比如:map;也可以定義具有多個參數的get方法;
例子
```
operator fun MutablePointer.set(index: Int, value: Int) { when (index) { 0 -> x = value 1 -> y = value else -> throw IndexOutOfBoundsException("Invalid params: $index") } } ```
3.2 in 的約定
用於檢測某個對象,是否符合某個集合,對應的函數是:contains
例子
```
data class Rectangle(val left: Pointer, val right: Pointer) operator fun Rectangle.contains(p: Pointer): Boolean { return p.x in left.x until right.x && p.y in left.y until right.y } fun main(args: Array<String>) { val rect = Rectangle(Pointer(10, 20), Pointer(50, 50)) println(Pointer(20, 48) in rect) } ```
in
右邊的對象將會調用contains
函數,in 左邊的對象,作為入參;
3.3 rangeTo 的約定
(0..10)創建一個閉區間,表示0到10的所有數字,共11個,
實際這里的..
調用的是rangeTo
函數;
方法簽名(Kotlin標准庫中)為,我沒找到:
3.4 for循環的in
for 循環中的in
是用來執行迭代 iterator
,這是一種約定;
也就是說 iterator
函數,可使用 in
運算符,來實現迭代;
定義在哪里的,還是沒找到;
2018-02-06
補充,找到了,其實也是一種約定(來自androidx.view.ViewGroup);
operator fun ViewGroup.iterator() = object : MutableIterator<View> { private var index = 0 override fun hasNext() = index < childCount override fun next() = getChildAt(index++) ?: throw IndexOutOfBoundsException() override fun remove() = removeViewAt(--index) }
4.方法調用補充
調用操作符
```
表達式 翻譯為
a() a.invoke() a(i) a.invoke(i) a(i,j) a.invoke(i,j) ```