Kotlin 之操作符重载
参考:
- kotlin in action
- kotlin 官方参考文档
运算符重载
Kotlin允许我们为自己的类型提供预定义的一组操作符实现(这些操作符都对应的成员函数或扩展函数),他们是一一对应的,如:
(+ 对应 plus);
通过这个操作符,如+,可调用plus 方法;
如:在Kotlin中,为类定义了一个plus
方法,按照约定,可以在该类型实例上通过+
运算符,来实现 调用 plus方法;
重载操作符的函数需要用 operator
关键字标记;
从以下类开始
data class Pointer(val x:Int, val y:Int)
1. 重载算术运算符
在Kotlin中,使用约定最直接的就是算术运算符了;对比java
,java只能用在基本类型中;
1.1 重载二元运算符
用于操作符重载的所有函数使用
operator
关键字标记,这里不是碰巧的;
a. 重载成员函数
为Pointer
类添加 +
号操作,把2个点的x,y
加在一起
```
operator fun plus(other:Pointer) :Pointer {
return Pointer(x + other.x, y + other.y)
}
```
b. 重载扩展函数
这就厉害了,可给第三方库的一些类,实现重载操作符了;
重要说明
Kotlin限定了只能重载哪些操作符,以及在类中定义的名字,这样就避免了操作符的滥用;
可重载的二元算术运算符
```
表达式 函数
a*b times
a/b div
a%b mod
a+b plus
a-b minus
```
c. 优先级的概念
与标准数字类型的运算符有着相同的优先级;
d.其他说明
定义运算符时,2个运算数,可以是不同的类型,比如如下:
```
operator fun div(scale:Float):Pointer {
return Pointer((x * scale).toInt(), (y * scale).toInt())
}
```
Kotlin运算符不支持
交换性
(比如:乘法的交换律)
比如:1.5 * pointer
与 pointer * 1.5
是不一样的;
同于运算数,运算符函数的返回类型也可以不一样,如:
```
operator fun Char.times(count:Int):String {
return toString().repeat(count)
}
```
同于普通函数,
operator
方法允许重载(形参参数类型不一样);
1.2 位运算
Kotlin中,没有为标准数字类型,定义任何位运算符;他们使用中缀
调用语法的常规函数;
比如:xor,and,or 等;
1.3 重载复合赋值运算符
+=, -=
这种被称为复合赋值运算符
,kotlin也是支持的;
在一些情况下,定义+=
运算可以修改变量所引用的对象,但不会重新分配引用,用于可变集合;
```
val nums = ArrayList<Int>()
nums += 58 // 类似调用add方法
println(nums)
```
Kotlin为标准可变集合定义plusAssign
函数(minusAssign,timesAssign)等,可以看下其源代码;
1.4 重载一元运算符
-a, +a
这种一元运算符,与上面的类似,函数名不能随意取
可重载的一元算术运算符
```
表达式 函数
+a unaryPlus
-a unaryMinus
!a not
++a,a++ inc
--a,a-- dec
```
例子:
```
operator fun unaryMinus() = Pointer(-x, -y)
// inc dec 编译器支持 ++a 与 a++
operator fun BigDecimal.inc() = this + BigDecimal.ONE
fun main(args: Array<String>) {
var n = BigDecimal.ZERO
println(n++) // 0
println(++n) // 2
}
```
2. 重载比较运算符
类似于算术运算符,在Kotlin中,可以对任何对象使用比较运算符(==、!=、 >、<)
等,可以不用像Java那种调用equals,compareTo
函数;
2.1 等号运算符 ==
Kotlin的约定原则之一是:使用==
会转换成equals
方法调用;但== 与 !=
更安全,会自动检测是否为 null,如果不为null,才进行判断;
即:a == b ===> a?.equals(b) ?: (b==null)
例子
```
val p = Pointer(1, 2)
val p2 = Pointer(1, 2)
println(p == p2)
```
equals
不需要 operator
,因为在Any里面标记过了;
2.2 恒等运算符 ===
恒等运算符等价于Java中的 ==
运算符:检查2个参数的是否是同一个对象的引用(基本类型判断值是否相同)
===
不能被重载
2.3 排序运算符 compareTo
Java中,如果对象需要比较,得使用Comparable
接口,不支持 > <
这种,
Kotlin中,可以使用> <
这种符号了, (<,>, <= ,>=)
会转换成 compareTo
约定调用;
即:a >= b =====> a.compareTo(b) >= 0
例子
```
class Person(val firstName: String, val lastName: String) : Comparable<Person> {
override fun compareTo(other: Person): Int {
// 先姓,再名
return compareValuesBy(this, other, Person::lastName,
Person::firstName)
}
}
```
在Kotlin中,可以直接使用java中实现Comparable
接口的类,采用更加简洁的运算符语法;
如:println("abc" < "bac")
3. 集合与区间的约定
处理集合最常见的一些操作,是通过下标来获取和设置元素,还有就是检查了;
这些kotlin中也是支持运算符操作的;
获取 a[1]
(下标操作符),可使用in
运算符来检查元素是否在集合或区间内;
3.1 通过下标来访问元素:[] get与set
下标运算符是一个约定,会转换成对应的 get 或 set方法的调用,比如:map
例子
get方法并用 operator
标记;
```
operator fun Pointer.get(i: Int): Int {
return when (i) {
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException("Invalid params: $i")
}
}
```
这个get方法,参数可以是任意类型,比如:map;也可以定义具有多个参数的get方法;
例子
```
operator fun MutablePointer.set(index: Int, value: Int) {
when (index) {
0 -> x = value
1 -> y = value
else -> throw IndexOutOfBoundsException("Invalid params: $index")
}
}
```
3.2 in 的约定
用于检测某个对象,是否符合某个集合,对应的函数是:
contains
例子
```
data class Rectangle(val left: Pointer, val right: Pointer)
operator fun Rectangle.contains(p: Pointer): Boolean {
return p.x in left.x until right.x &&
p.y in left.y until right.y
}
fun main(args: Array<String>) {
val rect = Rectangle(Pointer(10, 20), Pointer(50, 50))
println(Pointer(20, 48) in rect)
}
```
in
右边的对象将会调用contains
函数,in 左边的对象,作为入参;
3.3 rangeTo 的约定
(0..10)创建一个闭区间,表示0到10的所有数字,共11个,
实际这里的..
调用的是rangeTo
函数;
方法签名(Kotlin标准库中)为,我没找到:
3.4 for循环的in
for 循环中的in
是用来执行迭代 iterator
,这是一种约定;
也就是说 iterator
函数,可使用 in
运算符,来实现迭代;
定义在哪里的,还是没找到;
2018-02-06
补充,找到了,其实也是一种约定(来自androidx.view.ViewGroup);
operator fun ViewGroup.iterator() = object : MutableIterator<View> {
private var index = 0
override fun hasNext() = index < childCount
override fun next() = getChildAt(index++) ?: throw IndexOutOfBoundsException()
override fun remove() = removeViewAt(--index)
}
4.方法调用补充
调用操作符
```
表达式 翻译为
a() a.invoke()
a(i) a.invoke(i)
a(i,j) a.invoke(i,j)
```