Kotlin学习笔记5-7 其他-运算符重载

运算符重载

Kotlin官网:Other-Operator overloading
Kotlin支持重载运算符,运算符有对应固定名字的函数,可以定义为成员函数或者扩展函数,函数前加operator

一元运算

一元前置运算符

表达式转换
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()

编译器的转换步骤:

  • 判断a的类型,假设为T;
  • 寻找有operator修饰、名为unaryPlus()、没有参数、接收者为T(成员或扩展)的函数;
  • 如果没有找到这样的函数,编译器会报错;
  • 如果有这样的函数,函数返回值为R,则+a表达式整体的类型为R。

注意,对于基本类型有特殊优化,没有调用相应函数的性能损耗。
举个例子:

运算符重载

Kotlin官网:Other-Operator overloading
Kotlin支持重载运算符,运算符有对应固定名字的函数,可以定义为成员函数或者扩展函数,函数前加operator

一元运算

一元前置运算符

表达式转换
+aa.unaryPlus()
-aa.unaryMinus()
!aa.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 + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b), a.mod(b) (deprecated)
a..ba.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 bb.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] = ba.set(i, b)
a[i, j] = ba.set(i, j, b)
a[i_1, …, i_n] = ba.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 += ba.plusAssign(b)
a -= ba.minusAssign(b)
a *= ba.timesAssign(b)
a /= ba.divAssign(b)
a %= ba.remAssign(b), a.modAssign(b) (deprecated)

对于赋值运算的编译器执行步骤,以a += b为例:

  • 如果有右侧对应的函数:
    • 如果对应的二元运算符函数也存在,例如plus()函数之于plusAssign(),会报错;
    • 返回值必须为Unit,否则报错;
    • 生成代码a.plusAssign(b)
  • 生成代码`a = a + b,a + b的返回值必须为a的类型的子类。

Kotlin中,赋值运算不是表达式。

相等和不等运算符

表达式转换
a == ba?.equals(b) ?: (b === null)
a != b!(a?.equals(b) ?: (b === null))

注意:===!==不允许重载。
对于null有特殊处理,对于null == null永远为true,对于x == null,如果x为非空类型,用永远为false,不会执行x.equals()

比较运算符

表达式转换
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0

比较运算符转换成compareTo函数,要求返回Int型。

属性委托运算符

详见3-13委托属性

比较运算符

表达式转换
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0

比较运算符转换成compareTo函数,要求返回Int型。

属性委托运算符

详见3-13委托属性

中缀函数名调用

详见4-1函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值