操作符
操作符优先级
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 + 3 与 1 shl (2 + 3)
0 until n * 2 与 0 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)
}
详细参考:操作符重载