[关闭]
@cxm-2016 2017-02-01T19:21:37.000000Z 字数 2146 阅读 1984

Kotlin (二十七)——操作符重载

Kotlin



操作符重载(Operator overloading)

Kotlin 允许我们对数据类型的一组预定义的操作符提供实现函数. 这些操作符的表达符号是固定(比如 +*), 优先顺序也是固定的. 要实现这些操作符, 我们需要对相应的数据类型实现一个固定名称的 成员函数 或 扩展函数, 这里所谓"相应的数据类型", 对于二元操作符, 是指左侧操作数的类型, 对于一元操作符, 是指唯一一个操作数的类型.
用于实现操作符重载的函数应该使用 operator 修饰符进行标记.

约定

下面我们介绍与各种操作符的重载相关的约定.

一元操作符

表达式 翻译为
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

上表告诉我们说, 当编译器处理一元操作符时, 比如表达式 +a, 它将执行以下步骤:

注意, 这些操作符, 以其其它所有操作符, 都对 基本类型 进行了优化, 因此不会发生函数调用, 并由此产生性能损耗.

表达式 翻译为
a++ a.inc() (参见下文)
a-- a.dec() (参见下文)

这些操作符应该改变它们的接受者, 并且返回一个值(可选).

inc()/dec() 不应该改变接受者对象的值.
上文所谓"改变它们的接受者", 我们指的是改变 接受者变量, 而不是改变接受者对象的值.
{:.note}

对于 后缀 形式操作符, 比如 a++, 编译器解析时将执行以下步骤:

计算这个表达式所造成的影响是:

对于 a--, 计算步骤完全类似.

对于 前缀 形式的操作符 ++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)

方括号被翻译为, 使用适当个数的参数, 对 getset 函数的调用.

符号 翻译为
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, 编译器执行以下步骤:

注意: 在 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 类型.

对命名函数的中缀式调用

使用 中缀式函数调用, 我们可以模拟自定义的中缀操作符.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注