运算符重载
Kotlin官网:Other-Operator overloading
Kotlin支持重载运算符,运算符有对应固定名字的函数,可以定义为成员函数或者扩展函数,函数前加operator
。
一元运算
一元前置运算符
表达式 | 转换 |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
编译器的转换步骤:
- 判断a的类型,假设为T;
- 寻找有operator修饰、名为unaryPlus()、没有参数、接收者为T(成员或扩展)的函数;
- 如果没有找到这样的函数,编译器会报错;
- 如果有这样的函数,函数返回值为R,则+a表达式整体的类型为R。
注意,对于基本类型有特殊优化,没有调用相应函数的性能损耗。
举个例子:
运算符重载
Kotlin官网:Other-Operator overloading
Kotlin支持重载运算符,运算符有对应固定名字的函数,可以定义为成员函数或者扩展函数,函数前加operator
。
一元运算
一元前置运算符
表达式 | 转换 |
---|---|
+a | a.unaryPlus() |
-a | a.unaryMinus() |
!a | a.not() |
对于表格内表达式的编译步骤:
- 判断a的类型,假设为T;
- 寻找有operator修饰、名为unaryPlus()、没有参数、接收者为T(成员或扩展)的函数;
- 如果没有找到这样的函数,编译器会报错;
- 如果有这样的函数,函数返回值为R,则+a表达式整体的类型为R。
注意,对于基本类型有特殊优化,没有调用相应函数的性能损耗。
举个例子:
data class Point(val x: Int, val y: Int)
operator fun Point.unaryMinus() = Point(-x, -y)
val point = Point(10, 20)
println(-point) // prints "(-10, -20)"
自增和自减
表达式 | 转换 |
---|---|
a++ | a.inc() + see below |
a– | a.dec() + see below |
inc()函数或dec()函数需要返回一个值,赋值给调用++或–运算符的变量。对于调用者,表达式的值和原对象相同。
对于后置运算符,以a++为例,编译器处理如下:
- 判断a的类型,假设为T;
- 寻找有operator修饰、名为inc()、没有参数、接收者为T的函数;
- 检查返回值的类型是否为T的子类。
计算步骤:
- 将a的值存储到一个临时变量a0;
- 将a.inc()的结果赋值给a;
- 将a0作为表达式的返回时。
a--
的原理和步骤和a++完全相同。
对于前置运算符++a和–a运算步骤和前置的相似,区别在于:
- 将a.inc()赋值给a;
- 将a作为表达式的返回值。
二元运算
算术运算符
表达式 | 转换 |
---|---|
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) (deprecated) |
a..b | a.rangeTo(b) |
编译器只是简单转换成右侧,没有特殊处理。
其中,rem是Kotlin1.1中添加的,Kotlin1.0使用mod,在1.1中被废弃。
举个例子,Counter类重载+:
data class Counter(val dayIndex: Int) {
operator fun plus(increment: Int): Counter {
return Counter(dayIndex + increment)
}
}
In运算符
表达式 | 转换 |
---|---|
a in b | b.contains(a) |
a !in b | !b.contains(a) |
in和!in与其他运算符函数的区别是函数的接收者和参数顺序是颠倒的。
下标访问运算符
表达式 | 转换 |
---|---|
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) |
方括号转换成对应下标的get和set函数。
Invoke运算符
表达式 | 转换 |
---|---|
a() | a.invoke() |
a(i) | a.invoke(i) |
a(i, j) | a.invoke(i, j) |
a(i_1, …, i_n) | a.invoke(i_1, …, i_n) |
括号转换成invoke函数的参数。
赋值运算
表达式 | 转换 |
---|---|
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) (deprecated) |
对于赋值运算的编译器执行步骤,以a += b
为例:
- 如果有右侧对应的函数:
- 如果对应的二元运算符函数也存在,例如plus()函数之于plusAssign(),会报错;
- 返回值必须为Unit,否则报错;
- 生成代码
a.plusAssign(b)
;
- 生成代码`a = a + b,a + b的返回值必须为a的类型的子类。
Kotlin中,赋值运算不是表达式。
相等和不等运算符
表达式 | 转换 |
---|---|
a == b | a?.equals(b) ?: (b === null) |
a != b | !(a?.equals(b) ?: (b === null)) |
注意:===
和!==
不允许重载。
对于null有特殊处理,对于null == null
永远为true,对于x == null
,如果x为非空类型,用永远为false,不会执行x.equals()
。
比较运算符
表达式 | 转换 |
---|---|
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-13委托属性
比较运算符
表达式 | 转换 |
---|---|
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-13委托属性
中缀函数名调用
详见4-1函数