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 * 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) ```

Kotlin 之操作符重载的更多相关文章

  1. kotlin之操作符重载

    一元操作符 表达式 对应的函数 +a a.unaryPlus() -a a.unaryMinus() !a a.not() a++ a.inc() a-- a.dec() fun main(arg: ...

  2. Kotlin操作符重载:把标准操作加入到任何类中(KAD 17)

    作者:Antonio Leiva 时间:Mar 21, 2017 原文链接:https://antonioleiva.com/operator-overload-kotlin/ 就像其他每种语言一样, ...

  3. Kotlin——最详细的操作符与操作符重载详解(上)

    本篇文章为大家详细的介绍Koltin特有的操作符重载.或许对于有编程经验的朋友来说,操作符这个词绝对不陌生,就算没有任何编辑基础的朋友,数学中的算数运算符也绝不陌生.例如(+.-.*./.>.& ...

  4. c++ 操作符重载和友元

    操作符重载(operator overloading)是C++中的一种多态,C++允许用户自定义函数名称相同但参数列表不同的函数,这被称为函数重载或函数多态.操作符重载函数的格式一般为: operat ...

  5. paip.操作符重载的缺失 Java 的一个大缺点

    paip.操作符重载的缺失 Java 的一个大缺点 #----操作符重载的作用 1.提升用户体验 操作符重载..可以让代码更加自然.... 2.轻松实现代码代码移植 例如   java代码会直接移植到 ...

  6. C#中如何利用操作符重载和转换操作符

    操作符重载 有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成 ...

  7. 操作符重载.xml

    pre{ line-height:1; color:#1e1e1e; background-color:#d2d2d2; font-size:16px;}.sysFunc{color:#627cf6; ...

  8. [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)

    operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...

  9. C++一些注意点之操作符重载

    重载操作符需要注意 (1)重载操作符必须具有一个类类型操作数.不能重载内建类型的操作符. operator +(int,int);//这个是错误的,都为内建类型 operator +(int,clas ...

随机推荐

  1. [算法竞赛][2018][蓝桥杯][LanqiaoCA]第九届蓝桥杯A组

    题目1 标题:分数 1/1 + 1/2 + 1/4 + 1/8 + 1/16 + .... 每项是前一项的一半,如果一共有20项,求这个和是多少,结果用分数表示出来.类似:3/2当然,这只是加了前2项 ...

  2. linux系统编程之信号(三)

    今天继续对信号进行研究,话不多说,言归正传: 更多信号发送函数: 上节中我们已经接触到了一些信号的发送函数,这里更进一步学习一下其它的发送函数: alarm:只能发送SIGALRM信号 下面通过一个例 ...

  3. DevExpress GridControl 使用瀑布加载方式加载数据

    从事winform开发已经快三年了,这三年中两年使用DevExpress控件进行winform系统开发,对Dev控件有自己的一些思考,下面就常用的表格控件GridControl的分页进行一些讨论. 在 ...

  4. 《3+1团队》【Beta】Scrum meeting 2

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 3+1团队 团队博客地址 https://home.cnblogs.com/u/3-1group ...

  5. vue 中数据共享的方式

    1.父子组件的数据传递2.store模式 - 局部的数据共享3.vuex 中共享 state - 全局的数据共享

  6. read_excle

    Signature: pd.read_excel( ['io', 'sheet_name=0', 'header=0', 'skiprows=None', 'skip_footer=0', 'inde ...

  7. Python如何实现doc文件转换为docx文件?

    Python如何实现doc文件转换为docx文件? 在开发过程中遇到一个关于读写doc和docx的问题: 一个文件夹中有两种文件, 一种为doc结尾, 一种为docx结尾, 需要将这些文件全部重命名. ...

  8. SIGAI机器学习第二十二集 AdaBoost算法3

    讲授Boosting算法的原理,AdaBoost算法的基本概念,训练算法,与随机森林的比较,训练误差分析,广义加法模型,指数损失函数,训练算法的推导,弱分类器的选择,样本权重削减,实际应用. AdaB ...

  9. 016_Python3 函数

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这 ...

  10. OpenStack Restful API框架介绍

    1  pecan框架介绍 1.1  什么是pecan pecan是一个轻量级的python web框架,最主要的特点是提供了简单的配置即可创建一个wsgi对象并提供了基于对象的路由方式. 主要提供的功 ...