Kotlin 之操作符重载

参考:

  1. kotlin in action
  2. 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 * pointerpointer * 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)

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

推荐阅读更多精彩内容