Kotlin操作符重载与中缀表示法笔记

1.操作符重载

操作符重载在java中并没有这样的概念,它可以让我们为指定的类型提供预定义的一组操作符实现。这些操作符具有固定的符号表示(如+、* 或 in)和固定的优先级。怎样实现操作符重载呢?其实只要你实现一个固定名称的函数,然后用operator来修饰这个函数。查看Kotlin源码可以发现有大量的操作符重载的实现,我们来看看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 一元前缀操作符

表达式 翻译为
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

当编译器处理+a时,它执行以下步骤:

  • 确定a实例的类型,如果类似为T。
  • 在T类型中查找一个带有operator修饰符的无参函数unaryPlus(),可以是成员函数或者扩展函数。
  • 如果没有找到,则会发生编译错误。

下面代码展示下如何实现一个一元减运算符的示例:

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 递增与递减

表达式 翻译为
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 算术运算符

表达式 翻译为
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 中被弃用。
以下为示例:

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”操作符

表达式 翻译为
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 索引访问操作符

表达式 翻译为
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 广义赋值

表达式 翻译为
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)(已弃用)

通常来说,当你已经定义一个plus操作符时,Kotlin不仅仅支持+操作符,还同时支持+=操作了。重载+=操作符,除了实现plusAssign函数外,还需要函数返回值为Unit,而重载+操作符,是需要返回值的。当同时重载了+=和+操作符时,调用的时候会有编译错误,所以你只能保留一种操作符。如下:


operator

所以我们什么时候该用+操作符,什么时候该用+=呢?原则就是,如果你的类是一个mutable(可变化的)类,那么就使用+=操作符,反之就使用+操作符。查看源码可知MutableCollection就定义了plusAssign方法,而不是plus方法。


plusAssign

3.5 相等与不等操作符

表达式 翻译为
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))

Kotlin判断相等跟java是有区别的。Kotlin中判断值相等是用==,而java是调用equals方法。Kotlin中判断引用相等是用===,而java使用==。在Kotlin中null==null总是true,对于非空的x,x==null总是返回false而不会调用x.equals(null)。
当与null显示比较时,a==null会自动转换为a===null,注意:===和!==不可重载。

3.6 Elvis操作符 ?:

在Kotlin中,Elvis操作符特定是跟null比较。也就是说y = x?:0等价于val y = if (x!==null) x else 0。主要用于null的安全检查,Elvis操作符是一个二元运算符,如果第一个操作数不为null,则返回自己,否则返回第二个操作数。

在Kotlin中没有java中的三元运算符true?1:0,只有类似的`if (true) 1 else 0。而Evlis操作符是精简版的三元操作符。在java中使用三元运算符通常要重复变量两次,如下:

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

而在Kotlin中:

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

3.7 比较操作符

表达式 翻译为
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 的调用,这个函数需要返回 Int 值。

3.8 操作符优先级

优先级 标题 符号
最高 后缀(Postfix) ++, --, ., ?., ?
前缀(Prefix) -, +, ++, --, !, labelDefinition@
右手类型运算(Type RHS,right-hand side class type) :, as, as?
乘除去余(Multiplicative) *, /, %
加减(Additive) *, /, %
区间范围(Range) ..
infix函数 1 shl 2
Elvis操作符 ?:
命名检查符(Named checks) in, !in, is, !is
比较大小(Comparison) <, >, <=, >=
相等行判断(Equality) ==, !==
与(Conjunction) &&
或(Disjunction) ll
最低 赋值(Assignment) =, +=, -=, *=, /=, %=

4. 中缀表示法

函数还可以用中缀表示法调用,满足下面三个条件时:

  • 他们是成员函数或扩展函数
  • 他们只有一个参数
  • 他们使用infix关键字标注
    示例:
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语言基础笔记

Kotlin流程控制语句笔记

Kotlin操作符重载与中缀表示法笔记

Kotlin扩展函数和扩展属性笔记

Kotlin空指针安全(null-safety)笔记

Kotlin类型系统笔记

Kotlin面向对象编程笔记

Kotlin委托(Delegation)笔记

Kotlin泛型型笔记

Kotlin函数式编程笔记

Kotlin与Java互操作笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,168评论 9 118
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,132评论 0 13
  • 我一路看过千山和万水,我的脚踏遍天南和地北。 这不是我说的,这是今天晚上“简书福利社社长简东西”发的福利情报08的...
    qwemb阅读 728评论 2 3
  • 青春是一首歌,充满朝气、奋发向上的歌。站在青春里,遍地美好。朗朗书声,多彩画笔,翩翩舞蹈,激扬丽歌,都将成为...
    三石艺堂阅读 450评论 0 1
  • 全局安装 你可以将此文件放在任何地方。如果你把它放在系统的PATH目录中,你就能在全局访问它。 在类Unix系统中...
    mingminy阅读 3,397评论 0 0