Kotlin 之操作符重載


Kotlin 之操作符重載

 

參考:

  1. kotlin in action
  2. 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) ```


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM