溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Kotlin操作符重載的方法

發(fā)布時間:2022-04-18 10:36:17 來源:億速云 閱讀:263 作者:iii 欄目:開發(fā)技術(shù)

這篇“Kotlin操作符重載的方法”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Kotlin操作符重載的方法”文章吧。

算數(shù)運算操作符重載

在kotlin中我定義一個類

data class Point(val x: Int, val y: Int)

然后實例化兩個對象

val p1 = Point(3,5)
val p2 = Point(5,7)

想表示p1的元素x加上p2的元素x,p1的元素y,加上p2的元素y.然后輸出一個p3.

val p3 = Point(p1.x + p2.x, p2.y + p2.y)

以上這種寫法沒有任何問題。不過我們可以利用Kotlin擴展函數(shù)簡化上面的操作,我們給Point增加一個plus,并附加operator關(guān)鍵字。(增加operator的關(guān)鍵字是為了區(qū)分plus并不是一個普通的成員方法)

data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}

接下來再來實現(xiàn)上面的需求.

val p3 = p1 + p2

這樣表達(dá)起來更簡潔了。 另外我們可以把plus作為Point的擴展方法

data class Point(val x: Int, val y: Int)

operator fun Point.plus(other: Point): Point {
    return Point(x + other.x, y + other.y)
}

這種場景適用于Point存在于一個三方庫,我們并能修改其中的內(nèi)容. Kotlin中提供了以下操作符的重載. 只需要實現(xiàn)對應(yīng)的方法即可。

Kotlin操作符重載的方法

之前我們定一個了plus,參數(shù)是Point,實際上對于個操作符重載并不局限于同一種類型,接下來我們來定一個times,允許你去擴展Ponit.

data class Point(val x: Int, val y: Int)

operator fun Point.times(scale: Double): Point {
    return Point((x * scale).toInt(), (y * scale).toInt())
}

fun main(args: Array<String>) {
    val p = Point(10, 20)
    println(p * 1.5)
}

注意kotlin不支持交換性,例如我這里寫成1.5 * p這里是不允許的。除非你去定一個

operator fun Double.times(p: Point): Point

返回類型同樣也可以不是同一個類型,例如, 定義一個對char類型重載*操作符重復(fù)count后返回一個string.

operator fun Char.times(count: Int): String {
    return toString().repeat(count)
}

fun main(args: Array<String>) {
    println('a' * 3)
}

復(fù)合運算操作符重載

我們在編程過程中通常會去把這種寫法p = p + p1 寫成 p += p1 這種簡化寫法,在kotlin中同樣也支持這種+=操作符自定義操作。這種自定義運算操作符在什么場景下使用呢? 舉個例子,我們定義集合

val numbers = ArrayList<Int>()
numbers += 42
println(numbers[0])

以上寫法會感覺更加簡潔。 我們在集合中定義操作符重載方法plusAssign(這里還有minusAssign, timesAssign等等)

operator fun <T> MutableCollection<T>.plusAssign(element: T) {
    this.add(element)
}

不過kotlin-stblib庫已經(jīng)幫你實現(xiàn)好了關(guān)于集合的類似操作. 在集合中+,-會累加集合原始后返回一個新的集合,如果使用+=,-=, 集合是mutable,會在本集合直接修改內(nèi)容,如果集合是read-only,會返回一個拷貝后的修改集合。(這意味著如果集合是read-only,它的聲明必須要是var, 不然它不能接受新返回拷貝后的修改集合). 你可以使用單獨的元素或者集合(類型必須一致)進(jìn)行復(fù)合運算符操作和算數(shù)運算符.

val list = arrayListOf(1, 2)
list += 3                      
val newList = list + listOf(4, 5) 
println(list)
result : [1, 2, 3]
println(newList)
result : [1, 2, 3, 4, 5]

一元運算操作符重載

我們在編程過程中使用類似++a, a++, --a, a--同樣支持運算符重載。僅僅需要重寫下面的操作符函數(shù)即可

Kotlin操作符重載的方法

舉個例子

operator fun BigDecimal.inc() = this + BigDecimal.ONE

fun main(args: Array<String>) {
    var bd = BigDecimal.ZERO
    println(bd++)
    println(++bd)
}

這里注意到我只定一個inc(),同時也是支持bd++和++bd.

比較操作符重載

kotlin中還支持==, !=, >, <操作符重載. 對于==, !=我們重寫equals方法. 這里還是拿Point來舉栗子

data class Point(val x: Int, val y: Int)

我們這里聲明成了data類,這個關(guān)鍵字加上了編譯器會自動幫你實現(xiàn)equals方法,我們現(xiàn)在去掉,看看自己去寫equals怎么寫

class Point(val x: Int, val y: Int) {
    override fun equals(obj: Any?): Boolean {
        if (obj === this) return true      //1
        if (obj !is Point) return false
        return obj.x == x && obj.y == y
    }
}

fun main(args: Array<String>) {
    println(Point(10, 20) == Point(10, 20))
    println(Point(10, 20) != Point(5, 5))  //2
    println(null == Point(1, 2))
}

這里我們需要關(guān)注一個//1 obj === this,這個===操作符是比較兩個對象的引用是否一致,實際上和java中的==是一樣的。 之前我們提到的操作符重載都會加上一個operator關(guān)鍵字,這里為什么是override?因為它重寫了Any.class的equals方法.

Kotlin操作符重載的方法

這里看下//2!= 其實就是equals結(jié)果的取反. 除了=和!=之外這里還有>和<, 通過重寫compareTo可以實現(xiàn)

class Person(
        val firstName: String, val lastName: String
) : Comparable<Person> {

    override fun compareTo(other: Person): Int {
        return compareValuesBy(this, other,
            Person::lastName, Person::firstName)
    }
}

fun main(args: Array<String>) {
    val p1 = Person("Alice", "Smith")
    val p2 = Person("Bob", "Johnson")
    println(p1 < p2)
}

這里的compareValuesBy順便說說,它是kotlin-stblib提供的擴展函數(shù)

Kotlin操作符重載的方法

集合和區(qū)域的約定

在kotlin中我們可以使用類似于操作數(shù)組的方法操作集合,例如a[b]這種. 對于其它類,可以自定義操作符實現(xiàn)類似的操作

operator fun Point.get(index: Int): Int {
    return when(index) {
        0 -> x
        1 -> y
        else ->
            throw IndexOutOfBoundsException("Invalid coordinate $index")
    }
}

fun main(args: Array<String>) {
    val p = Point(10, 20)
    println(p[1])
}

我們對于賦值操作同樣也可以通過自定義operator

data class MutablePoint(var x: Int, var y: Int)

operator fun MutablePoint.set(index: Int, value: Int) {
    when(index) {
        0 -> x = value
        1 -> y = value
        else ->
            throw IndexOutOfBoundsException("Invalid coordinate $index")
    }
}

fun main(args: Array<String>) {
    val p = MutablePoint(10, 20)
    p[1] = 42
    println(p)
}

另外一個知識點是自定義in操作符

Kotlin操作符重載的方法

in對于的contains函數(shù),判斷一個元素是否屬于一個范圍里.

data class Point(val x: Int, val y: Int)

data class Rectangle(val upperLeft: Point, val lowerRight: Point)

operator fun Rectangle.contains(p: Point): Boolean {
    return p.x in upperLeft.x until lowerRight.x &&
           p.y in upperLeft.y until lowerRight.y
}

fun main(args: Array<String>) {
    val rect = Rectangle(Point(10, 20), Point(50, 50))
    println(Point(20, 30) in rect)
    println(Point(5, 5) in rect)
}

迭代運算符重載

我們平時使用的

for (x in list) { ... }

將被轉(zhuǎn)換為 list.iterator() 的調(diào)用,然后重復(fù)調(diào)用 hasNext 和 next 方法,就像在 Java 中一樣。 請注意,在 Kotlin 中,它也是一種約定,這意味著可以將迭代器方法定義為擴展。這就解釋了為什么可以迭代常規(guī) Java 字符串:kotlin-stblib 在 Char-Sequence(String 的超類)上定義了一個擴展函數(shù)迭代器:

operator fun CharSequence.iterator(): CharIterator 
>>> for (c in "abc") {}

其它類型也可以通過自定義iterator實現(xiàn)自己類特定的操作。

import java.util.Date
import java.time.LocalDate

operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> =
        object : Iterator<LocalDate> {
            var current = start

            override fun hasNext() =
                current <= endInclusive

            override fun next() = current.apply {
                current = plusDays(1)
            }
        }

fun main(args: Array<String>) {
    val newYear = LocalDate.ofYearDay(2017, 1)
    val daysOff = newYear.minusDays(1)..newYear
    for (dayOff in daysOff) { println(dayOff) }
}

解構(gòu)聲明

這個操作可以分解一個對象中成員,例如

>>> val p = Point(10, 20)
>>> val (x, y) = p             
>>> println(x)
10
>>> println(y)
20

解構(gòu)聲明看起來有點像變量聲明,不過它組合了多個變量值。實際上它在kotlin中也屬于自定義操作符.去解構(gòu)多個變量需要定義componentN,N是變量的位置.

Kotlin操作符重載的方法

class Point(val x: Int, val y: Int) {
    operator fun component1() = x
    operator fun component2() = y
}

對于data類,解構(gòu)已經(jīng)幫你聲明好了 另外解構(gòu)聲明還可以用在循環(huán)中

fun printEntries(map: Map<String, String>) {
    for ((key, value) in map) {
        println("$key -> $value")
    }
}

fun main(args: Array<String>) {
    val map = mapOf("Oracle" to "Java", "JetBrains" to "Kotlin")
    printEntries(map)
}

Map中包含了擴展方法component1,component2返回key和value. 實際上你可以將上面的循環(huán)部分翻譯成

for (entry in map.entries) {
    val key = entry.component1()
    val value = entry.component2()
    // ...
}

以上就是關(guān)于“Kotlin操作符重載的方法”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI