Kotlin操作符重載與中綴表示法筆記

1.操作符重載

操作符重載在java中并沒有這樣的概念饵逐,它可以讓我們?yōu)橹付ǖ念愋吞峁╊A(yù)定義的一組操作符實(shí)現(xiàn)。這些操作符具有固定的符號表示(如+嚷辅、* 或 in)和固定的優(yōu)先級。怎樣實(shí)現(xiàn)操作符重載呢缤底?其實(shí)只要你實(shí)現(xiàn)一個(gè)固定名稱的函數(shù),然后用operator來修飾這個(gè)函數(shù)番捂。查看Kotlin源碼可以發(fā)現(xiàn)有大量的操作符重載的實(shí)現(xiàn),我們來看看Int類型做了那些操作符重載江解。

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public operator fun compareTo(other: Byte): Int

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public operator fun compareTo(other: Short): Int

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public override operator fun compareTo(other: Int): Int

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public operator fun compareTo(other: Long): Int

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public operator fun compareTo(other: Float): Int

    /**
     * Compares this value with the specified value for order.
     * Returns zero if this value is equal to the specified other value, a negative number if it's less than other,
     * or a positive number if it's greater than other.
     */
    public operator fun compareTo(other: Double): Int

    /** Adds the other value to this value. */
    public operator fun plus(other: Byte): Int
    /** Adds the other value to this value. */
    public operator fun plus(other: Short): Int
    /** Adds the other value to this value. */
    public operator fun plus(other: Int): Int
    /** Adds the other value to this value. */
    public operator fun plus(other: Long): Long
    /** Adds the other value to this value. */
    public operator fun plus(other: Float): Float
    /** Adds the other value to this value. */
    public operator fun plus(other: Double): Double

    /** Subtracts the other value from this value. */
    public operator fun minus(other: Byte): Int
    /** Subtracts the other value from this value. */
    public operator fun minus(other: Short): Int
    /** Subtracts the other value from this value. */
    public operator fun minus(other: Int): Int
    /** Subtracts the other value from this value. */
    public operator fun minus(other: Long): Long
    /** Subtracts the other value from this value. */
    public operator fun minus(other: Float): Float
    /** Subtracts the other value from this value. */
    public operator fun minus(other: Double): Double

    /** Multiplies this value by the other value. */
    public operator fun times(other: Byte): Int
    /** Multiplies this value by the other value. */
    public operator fun times(other: Short): Int
    /** Multiplies this value by the other value. */
    public operator fun times(other: Int): Int
    /** Multiplies this value by the other value. */
    public operator fun times(other: Long): Long
    /** Multiplies this value by the other value. */
    public operator fun times(other: Float): Float
    /** Multiplies this value by the other value. */
    public operator fun times(other: Double): Double

    /** Divides this value by the other value. */
    public operator fun div(other: Byte): Int
    /** Divides this value by the other value. */
    public operator fun div(other: Short): Int
    /** Divides this value by the other value. */
    public operator fun div(other: Int): Int
    /** Divides this value by the other value. */
    public operator fun div(other: Long): Long
    /** Divides this value by the other value. */
    public operator fun div(other: Float): Float
    /** Divides this value by the other value. */
    public operator fun div(other: Double): Double

    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Byte): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Short): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Int): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Long): Long
    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Float): Float
    /** Calculates the remainder of dividing this value by the other value. */
    @Deprecated("Use rem(other) instead", ReplaceWith("rem(other)"), DeprecationLevel.WARNING)
    public operator fun mod(other: Double): Double

    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Byte): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Short): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Int): Int
    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Long): Long
    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Float): Float
    /** Calculates the remainder of dividing this value by the other value. */
    @SinceKotlin("1.1")
    public operator fun rem(other: Double): Double

    /** Increments this value. */
    public operator fun inc(): Int
    /** Decrements this value. */
    public operator fun dec(): Int
    /** Returns this value. */
    public operator fun unaryPlus(): Int
    /** Returns the negative of this value. */
    public operator fun unaryMinus(): Int

     /** Creates a range from this value to the specified [other] value. */
    public operator fun rangeTo(other: Byte): IntRange
     /** Creates a range from this value to the specified [other] value. */
    public operator fun rangeTo(other: Short): IntRange
     /** Creates a range from this value to the specified [other] value. */
    public operator fun rangeTo(other: Int): IntRange
     /** Creates a range from this value to the specified [other] value. */
    public operator fun rangeTo(other: Long): LongRange

    /** Shifts this value left by the [bitCount] number of bits. */
    public infix fun shl(bitCount: Int): Int
    /** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with copies of the sign bit. */
    public infix fun shr(bitCount: Int): Int
    /** Shifts this value right by the [bitCount] number of bits, filling the leftmost bits with zeros. */
    public infix fun ushr(bitCount: Int): Int
    /** Performs a bitwise AND operation between the two values. */
    public infix fun and(other: Int): Int
    /** Performs a bitwise OR operation between the two values. */
    public infix fun or(other: Int): Int
    /** Performs a bitwise XOR operation between the two values. */
    public infix fun xor(other: Int): Int

2. 一元操作

2.1 一元前綴操作符

表達(dá)式 翻譯為
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

當(dāng)編譯器處理+a時(shí)设预,它執(zhí)行以下步驟:

  • 確定a實(shí)例的類型,如果類似為T犁河。
  • 在T類型中查找一個(gè)帶有operator修飾符的無參函數(shù)unaryPlus()鳖枕,可以是成員函數(shù)或者擴(kuò)展函數(shù)。
  • 如果沒有找到桨螺,則會(huì)發(fā)生編譯錯(cuò)誤宾符。

下面代碼展示下如何實(shí)現(xiàn)一個(gè)一元減運(yùn)算符的示例:

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

operator fun Point.unaryMinus() : Point = Point(-x, -y)

fun main(args: Array<String>) {
    val p = Point(1, 2)
    println(p)  //打印Point(x=1, y=2)
    println(-p)  //打印Point(x=-1, y=-2)
}

2.2 遞增與遞減

表達(dá)式 翻譯為
a++ a.inc()
a-- a.dec()

下面示例下用法:

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

operator fun Point.unaryMinus() : Point = Point(-x, -y)

operator fun Point.inc(): Point = Point(x + 1, y + 1)

operator fun Point.dec(): Point = Point(x - 1, y - 1)

3. 二元操作符

3.1 算術(shù)運(yùn)算符

表達(dá)式 翻譯為
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 運(yùn)算符魏烫。Kotlin 1.0 使用 mod 運(yùn)算符,它在 Kotlin 1.1 中被棄用肝箱。
以下為示例:

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

operator fun Point.unaryMinus() : Point = Point(-x, -y)

operator fun Point.inc(): Point = Point(x + 1, y + 1)

operator fun Point.dec(): Point = Point(x - 1, y - 1)

operator fun Point.plus(point: Point): Point = Point(x + point.x, y + point.y)

operator fun Point.minus(point: Point): Point = Point(x - point.x, y - point.y)

operator fun Point.times(point: Point): Point = Point(x * point.x, y * point.y)

3.2 “in”操作符

表達(dá)式 翻譯為
a in b b.contains(a)
a !in b !b.contains(a)

以下為示例代碼:

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

data class Rectangle(val x: Int, val y: Int, val width: Int, val height: Int)

operator fun Point.unaryMinus() : Point = Point(-x, -y)

operator fun Point.inc(): Point = Point(x + 1, y + 1)

operator fun Point.dec(): Point = Point(x - 1, y - 1)

operator fun Point.plus(point: Point): Point = Point(x + point.x, y + point.y)

operator fun Point.minus(point: Point): Point = Point(x - point.x, y - point.y)

operator fun Point.times(point: Point): Point = Point(x * point.x, y * point.y)

operator fun Rectangle.contains(point: Point): Boolean = point.x > x && point.x <x +width && point.y > y && point.y < y +height

fun main(args: Array<String>) {
    val p = Point(1, 2)
    val rectangle = Rectangle(0, 0, 2,3)
    println(p in rectangle)  //打印true
}

3.3 索引訪問操作符

表達(dá)式 翻譯為
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)

3.4 廣義賦值

表達(dá)式 翻譯為
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)(已棄用)

通常來說哄褒,當(dāng)你已經(jīng)定義一個(gè)plus操作符時(shí),Kotlin不僅僅支持+操作符煌张,還同時(shí)支持+=操作了呐赡。重載+=操作符,除了實(shí)現(xiàn)plusAssign函數(shù)外骏融,還需要函數(shù)返回值為Unit链嘀,而重載+操作符,是需要返回值的档玻。當(dāng)同時(shí)重載了+=和+操作符時(shí)怀泊,調(diào)用的時(shí)候會(huì)有編譯錯(cuò)誤,所以你只能保留一種操作符窃肠。如下:


operator

所以我們什么時(shí)候該用+操作符包个,什么時(shí)候該用+=呢?原則就是冤留,如果你的類是一個(gè)mutable(可變化的)類碧囊,那么就使用+=操作符,反之就使用+操作符纤怒。查看源碼可知MutableCollection就定義了plusAssign方法糯而,而不是plus方法。


plusAssign

3.5 相等與不等操作符

表達(dá)式 翻譯為
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))

Kotlin判斷相等跟java是有區(qū)別的泊窘。Kotlin中判斷值相等是用==熄驼,而java是調(diào)用equals方法像寒。Kotlin中判斷引用相等是用===,而java使用==瓜贾。在Kotlin中null==null總是true诺祸,對于非空的x,x==null總是返回false而不會(huì)調(diào)用x.equals(null)祭芦。
當(dāng)與null顯示比較時(shí)筷笨,a==null會(huì)自動(dòng)轉(zhuǎn)換為a===null,注意:===和!==不可重載龟劲。

3.6 Elvis操作符 ?:

在Kotlin中胃夏,Elvis操作符特定是跟null比較。也就是說y = x?:0等價(jià)于val y = if (x!==null) x else 0昌跌。主要用于null的安全檢查仰禀,Elvis操作符是一個(gè)二元運(yùn)算符,如果第一個(gè)操作數(shù)不為null蚕愤,則返回自己答恶,否則返回第二個(gè)操作數(shù)。

在Kotlin中沒有java中的三元運(yùn)算符true?1:0审胸,只有類似的`if (true) 1 else 0亥宿。而Evlis操作符是精簡版的三元操作符。在java中使用三元運(yùn)算符通常要重復(fù)變量兩次砂沛,如下:

String name = ...;
String displayName = name !=null ? name : "Unknown";

而在Kotlin中:

val name = ...
val displayName = name?:"Unkown"

3.7 比較操作符

表達(dá)式 翻譯為
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0

所有的比較都轉(zhuǎn)換為對 compareTo 的調(diào)用烫扼,這個(gè)函數(shù)需要返回 Int 值。

3.8 操作符優(yōu)先級

優(yōu)先級 標(biāo)題 符號
最高 后綴(Postfix) ++, --, ., ?., ?
前綴(Prefix) -, +, ++, --, !, labelDefinition@
右手類型運(yùn)算(Type RHS碍庵,right-hand side class type) :, as, as?
乘除去余(Multiplicative) *, /, %
加減(Additive) *, /, %
區(qū)間范圍(Range) ..
infix函數(shù) 1 shl 2
Elvis操作符 ?:
命名檢查符(Named checks) in, !in, is, !is
比較大杏称蟆(Comparison) <, >, <=, >=
相等行判斷(Equality) ==, !==
與(Conjunction) &&
或(Disjunction) ll
最低 賦值(Assignment) =, +=, -=, *=, /=, %=

4. 中綴表示法

函數(shù)還可以用中綴表示法調(diào)用,滿足下面三個(gè)條件時(shí):

  • 他們是成員函數(shù)或擴(kuò)展函數(shù)
  • 他們只有一個(gè)參數(shù)
  • 他們使用infix關(guān)鍵字標(biāo)注
    示例:
data class Point(var x: Int, var y: Int)

data class Rectangle(val x: Int, val y: Int, val width: Int, val height: Int)

operator fun Point.unaryMinus() : Point = Point(-x, -y)

operator fun Point.inc(): Point = Point(x + 1, y + 1)

operator fun Point.dec(): Point = Point(x - 1, y - 1)

operator fun Point.plusAssign(point: Point) {
    x += point.x
    y += point.y

}

operator fun Point.minus(point: Point): Point = Point(x - point.x, y - point.y)

operator fun Point.times(point: Point): Point = Point(x * point.x, y * point.y)

operator fun Rectangle.contains(point: Point): Boolean = point.x > x && point.x <x +width && point.y > y && point.y < y +height

infix fun Point.mut(point: Point): Point = Point(x * point.x, y * point.y)

fun main(args: Array<String>) {
    var x = Point(1, 2)
    var y = Point(3, 6)

    println(x mut y)  //打印Point(x=3, y=12)

}

Kotlin語言基礎(chǔ)筆記

Kotlin流程控制語句筆記

Kotlin操作符重載與中綴表示法筆記

Kotlin擴(kuò)展函數(shù)和擴(kuò)展屬性筆記

Kotlin空指針安全(null-safety)筆記

Kotlin類型系統(tǒng)筆記

Kotlin面向?qū)ο缶幊坦P記

Kotlin委托(Delegation)筆記

Kotlin泛型型筆記

Kotlin函數(shù)式編程筆記

Kotlin與Java互操作筆記

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末静浴,一起剝皮案震驚了整個(gè)濱河市堰氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苹享,老刑警劉巖双絮,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異得问,居然都是意外死亡囤攀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門宫纬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焚挠,“玉大人,你說我怎么就攤上這事漓骚◎蛳危” “怎么了榛泛?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長噩斟。 經(jīng)常有香客問我曹锨,道長,這世上最難降的妖魔是什么剃允? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任艘希,我火速辦了婚禮,結(jié)果婚禮上硅急,老公的妹妹穿的比我還像新娘。我一直安慰自己佳遂,他們只是感情好营袜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丑罪,像睡著了一般荚板。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吩屹,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天跪另,我揣著相機(jī)與錄音,去河邊找鬼煤搜。 笑死免绿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的擦盾。 我是一名探鬼主播嘲驾,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼迹卢!你這毒婦竟也來了辽故?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤腐碱,失蹤者是張志新(化名)和其女友劉穎誊垢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體症见,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喂走,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筒饰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缴啡。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瓷们,靈堂內(nèi)的尸體忽然破棺而出业栅,到底是詐尸還是另有隱情秒咐,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布碘裕,位于F島的核電站携取,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏帮孔。R本人自食惡果不足惜雷滋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望文兢。 院中可真熱鬧晤斩,春花似錦就乓、人聲如沸僧家。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽兼呵。三九已至兔辅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間击喂,已是汗流浹背维苔。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懂昂,地道東北人介时。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像忍法,于是被迫代替她去往敵國和親潮尝。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 人生苦多饿序,快來 Kotlin 勉失,快速學(xué)習(xí)Kotlin! 什么是Kotlin原探? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,146評論 9 118
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)乱凿,也就是一...
    悟名先生閱讀 4,118評論 0 13
  • 我一路看過千山和萬水,我的腳踏遍天南和地北咽弦。 這不是我說的徒蟆,這是今天晚上“簡書福利社社長簡東西”發(fā)的福利情報(bào)08的...
    qwemb閱讀 725評論 2 3
  • 青春是一首歌,充滿朝氣型型、奮發(fā)向上的歌段审。站在青春里,遍地美好闹蒜。朗朗書聲寺枉,多彩畫筆抑淫,翩翩舞蹈,激揚(yáng)麗歌姥闪,都將成為...
    三石藝堂閱讀 449評論 0 1
  • 全局安裝 你可以將此文件放在任何地方始苇。如果你把它放在系統(tǒng)的PATH目錄中,你就能在全局訪問它筐喳。 在類Unix系統(tǒng)中...
    mingminy閱讀 3,387評論 0 0