Kotlin操作符重载

操作符

操作符优先级

Kotlin操作符的优先级如下图所示:

为实现这些的操作符,Kotlin为二元操作符左侧的类型和一元操作符的参数类型,提供了相应的函数或扩展函数。

例如在kotlin/core/builtins/native/kotlin/Primitives.kt代码中,对基本类型Int的操作符的实现代码如下:

public class Int private constructor() : Number(), Comparable<Int> {
    ...
    public operator fun compareTo(other: Byte): Int
    public operator fun compareTo(other: Short): Int
    public override operator fun compareTo(other: Int): Int
    public operator fun compareTo(other: Long): Int
    public operator fun compareTo(other: Float): Int
    public operator fun compareTo(other: Double): Int
    public operator fun plus(other: Byte): Int
    public operator fun plus(other: Short): Int
    public operator fun plus(other: Int): Int/
    public operator fun plus(other: Long): Long
    public operator fun plus(other: Float): Float
    public operator fun plus(other: Double): Double
    public operator fun minus(other: Byte): Int
    public operator fun minus(other: Short): Int
    public operator fun minus(other: Int): Int
    public operator fun minus(other: Long): Long
    public operator fun minus(other: Float): Float
    public operator fun minus(other: Double): Double
    …
    public override fun toByte(): Byte
    public override fun toChar(): Char
    public override fun toShort(): Short
    public override fun toInt(): Int
    public override fun toLong(): Long
    public override fun toFloat(): Float
    public override fun toDouble(): Double
}

操作符重载

从上面代码可以看出,重载操作符的函数需要用operator修饰符标记。

一元操作

一元操作符(unary operation),包括前缀、递增和递减

前缀操作符


例如,当编译器处理表达式+a时,将执行以下步骤:

1)确定a的类型,令其为T。

2)为接收者T查找一个带有operator修饰符的无参函数unaryPlus(),即成员函数或扩展函数。

3)如果函数不存在或不明确,则导致编译错误。

4)如果函数存在且其返回类型为R,则表达式+a具有类型R。

编译器对这些操作以及所有其他操作都针对基本类型做了优化,不会引入函数调用的开销。
示例:

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

//简便写法:operator fun Point.unaryMinus() = Point(-x, -y)
operator fun Point.unaryMinus(): Point {
    return Point(-x, -y)
}

fun main(args: Array<String>) {
    val p = Point(10, 20)
    /*
       -p -> p.unaryMinus()
     */
    println(-p) //Point(x=-10, y=-20)
}

递增和递减


inc()和dec()函数必须返回一个值,它用于赋值给使用++或–操作的变量。
编译器解析后缀形式的操作符,例如a++(a–同理),步骤:

1)确定a的类型,令其为T。

2)查找一个适用于类型为T的接收者的、带有operator修饰符的无参数函数inc()。

3)检查函数的返回类型是T的子类型。

计算表达式的步骤:

1)把a的初始值存储到临时存储a_中。

2)把a.inc()结果赋值给a。

3)把a_作为表达式的结果返回。

对于前缀形式++a和–a解析步骤类似,但是返回值是取新值来返回:

1)把a.inc()结果赋值给a。

2)把a的新值a+1作为表达式结果返回。

二元操作

算术运算符


注意:自 Kotlin 1.1 起支持 rem 运算符。Kotlin 1.0 使用 mod 运算符,它在 Kotlin 1.1 中被弃用。
示例:

data class Counter(val dayIndex: Int) {
    operator fun plus(increment: Int): Counter {
        return Counter(dayIndex + increment)
    }
}

fun main(args: Array<String>) {
    val counter = Counter(3)
    println(counter + 3) // Counter(dayIndex=6)
}

“In” 操作符

索引访问操作符

方括号转换为调用带有适当数量参数的 get 和 set。

中缀操作符

标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。
中缀函数必须满足以下要求:

它们必须是成员函数或扩展函数;

它们必须只有一个参数;

其参数不得接受可变数量的参数且不能有默认值。

中缀函数调用的优先级低于算术操作符、类型转换以及 rangeTo 操作符。
以下表达式是等价的:

1 shl 2 + 31 shl (2 + 3)
0 until n * 20 until (n * 2)
xs union ys as Set<*> 与 xs union (ys as Set<*>)

另一方面,中缀函数调用的优先级高于布尔操作符 && 与 ||、is- 与 in- 检测以及其他一些操作符。这些表达式也是等价的:

a && b xor c 与 a && (b xor c)
a xor b in c 与 (a xor b) in c

自定义infix函数来实现中缀操作符:

data class Person(val name: String, val age: Int)

infix fun Person.grow(years: Int): Person {
    return Person(name, age + years)
}

fun main(args: Array<String>) {
    val person = Person("Jack", 20)
    println(person.grow(2)) // Person(name=Jack, age=22)
    println(person grow 2) // Person(name=Jack, age=22)
}

详细参考:操作符重载


   转载规则


《Kotlin操作符重载》 congwiny 采用 知识共享署名 4.0 国际许可协议 进行许可。
评论
 上一篇
Kotlin解构声明 Kotlin解构声明
解构声明:这个功能允许你展开单个复合值,并使用它来初始化多个单独的变量。任何表达式都可以出现在解构声明的右侧,只要可以对它调用所需数量的 component 函数即可。 /** * 要在解构声明中初始化每个变量,会调用名为componen
2019-09-09
下一篇 
Kotlin反射的使用 Kotlin反射的使用
反射反射(Reflection)是程序的自我分析能力,通过反射机制能够动态读取一个类的信息,可以确定类中有哪些函数、构造函数以及属性,并且能够在运行时动态加载类。 在Kotlin中有两种方式来实现反射的功能。一种是调用Java的反射包jav
2019-08-30
  目录