@cxm-2016
2017-02-01T19:21:37.000000Z
字数 2146
阅读 1984
Kotlin
Kotlin 允许我们对数据类型的一组预定义的操作符提供实现函数. 这些操作符的表达符号是固定(比如 +
或 *
), 优先顺序也是固定的. 要实现这些操作符, 我们需要对相应的数据类型实现一个固定名称的 成员函数 或 扩展函数, 这里所谓"相应的数据类型", 对于二元操作符, 是指左侧操作数的类型, 对于一元操作符, 是指唯一一个操作数的类型.
用于实现操作符重载的函数应该使用 operator
修饰符进行标记.
下面我们介绍与各种操作符的重载相关的约定.
表达式 | 翻译为 |
---|---|
+a |
a.unaryPlus() |
-a |
a.unaryMinus() |
!a |
a.not() |
上表告诉我们说, 当编译器处理一元操作符时, 比如表达式 +a
, 它将执行以下步骤:
a
的类型, 假设为 T
.operator
修饰符, 无参数的 unaryPlus()
函数, 而且函数的接受者类型为 T
, 也就是说, T
类型的成员函数或扩展函数.R
, 则表达式 +a
的类型为 R
.注意, 这些操作符, 以其其它所有操作符, 都对 基本类型 进行了优化, 因此不会发生函数调用, 并由此产生性能损耗.
表达式 | 翻译为 |
---|---|
a++ |
a.inc() (参见下文) |
a-- |
a.dec() (参见下文) |
这些操作符应该改变它们的接受者, 并且返回一个值(可选).
inc()/dec()
不应该改变接受者对象的值.
上文所谓"改变它们的接受者", 我们指的是改变 接受者变量, 而不是改变接受者对象的值.
{:.note}
对于 后缀 形式操作符, 比如 a++
, 编译器解析时将执行以下步骤:
a
的类型, 假设为 T
.operator
修饰符, 无参数的 inc()
函数, 而且函数的接受者类型为 T
.R
, 那么它必须是 T
的子类型.计算这个表达式所造成的影响是:
a
的初始值保存到临时变量 a0
中,a.inc()
的结果赋值给 a
,a0
, 作为表达式的计算结果值.对于 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.mod(b) |
a..b |
a.rangeTo(b) |
对于上表中的操作符, 编译器只是简单地解析 翻译为 列中的表达式.
表达式 | 翻译为 |
---|---|
a in b |
b.contains(a) |
a !in b |
!b.contains(a) |
对于 in
和 !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
函数的调用.
符号 | 翻译为 |
---|---|
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.modAssign(b) |
{:#assignments}
对于赋值操作符, 比如 a += b
, 编译器执行以下步骤:
plusAssign()
来说, plus()
函数) 也可用, 报告错误(歧义).Unit
, 否则报告错误.a.plusAssign(b)
的代码 a = a + b
的代码(这里包括类型检查: a + b
的类型必须是 a
的子类型).注意: 在 Kotlin 中, 赋值操作 不是 表达式.
{:#Equals}
表达式 | 翻译为 |
---|---|
a == b |
a?.equals(b) ?: b === null |
a != b |
!(a?.equals(b) ?: b === null) |
注意: ===
和 !==
(同一性检查) 操作符不允许重载, 因此对这两个操作符不存在约定
==
操作符是特殊的: 它被翻译为一个复杂的表达式, 其中包括对 null
值的判断, 而且, null == null
的判断结果为 true
.
符号 | 翻译为 |
---|---|
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
类型.
使用 中缀式函数调用, 我们可以模拟自定义的中缀操作符.