Kotlin Vocabulary | 操作符重载
操作符重载
https://kotlinlang.org/docs/reference/operator-overloading.html
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class Choir {
private val singers = mutableListOf<Singer>()
fun addSinger(singer: Singer) {
singers.add(singer)
}
...
}
choir.addSinger(singer)
choir += singer
接着往下读,您会知道:
如何在 Kotlin 中通过操作符重载实现这一点; 什么样的操作符可以被实现以及在 Android 的哪些场景下使用操作符会更有优势; 在实现操作符重载时要注意的最佳实践方法; Kotlin 编译器如何实现操作符重载。
操作符重载的基础
通过操作符重载,可以实现任意类型的一系列预定义操作符。操作符可以通过成员函数或者使用相应的成员函数的扩展函数来重载。比如: + 操作符可以通过 plus() 函数进行重载,+= 操作符可以通过 plusAssign() 函数进行重载。注意,操作符之间不会相互影响: 如果您重载了 +,是不会影响到 ++。
要重载一个操作符,您需要在 fun 的前面添加 operator 关键字,然后指定您想重载的操作符。如果您不添加 operator 关键字,编译器会把它当作一个普通的 Kotlin 函数来处理,甚至不会进行编译!
以下是 Kotlin 中可以重载的操作符:
请参见相关文档
相关文档
https://kotlinlang.org/docs/reference/operator-overloading.html
怎么做
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class Choir {
private val singers = mutableListOf<Singer>()
operator fun plusAssign(singer: Singer) {
singers.add(singer)
}
}
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
data class Singer(val name: String)
fun main() {
val choir = Choir()
val singerMeghan = Singer("Meghan")
choir += singerMeghan
}
您希望重载其他哪些操作符?
通常情况下您需要的操作符不止一个,但是重载一个自定义类型的所有操作符可能是没有任何意义的。过度的使用操作符重载会导致代码的可读性变差。所以需要多花点时间思考,对哪些操作符进行重载,可以提升代码的可读性。
我们重载 += 操作符是为了将某人加入合唱团,但我们可能也想看看这个人是否已经是合唱团的成员。要实现这一点,我们需要重载 contains 函数,这样我们就可以使用 in 操作符。
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
operator fun contains(s: Singer) : Boolean {
return singers.contains(s)
}
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
data class Singer(val name: String)
fun main() {
val choir = Choir()
val singerMeghan = Singer("Meghan")
choir += singerMeghan
if(singerMeghan in choir){
println("Meghan is a part of the choir!")
}
}
扩展中的操作符重载
也可以通过扩展函数来使用操作符重载。在这个示例中,我们重载了 ViewGroup 的 += 操作符:
operator fun ViewGroup.plusAssign(other: View) = addView(other)
现在给 viewGroup 添加一个 view 是如此的简单!
viewGroup += view
来自其他语言的最佳实践
简洁性并不总是意味着更易读的代码。想一下,如果您的代码中加入了操作符重载,那么您的代码是不是真的会更加易读; 如果重载的结果在语言的上下文中没有什么意义,或者有任何不清晰的地方,您应该考虑使用函数来代替。比如,如果您添加了两本书,那么最终的结果会是什么,并不是马上就能看清楚的。会是一本新书吗?它们会如何组合?如果有疑问,那么您应该用函数来代替; 如果一个操作符被重载了,那么应该考虑一下与之对应的其他操作符也要被重载。比如,如果重载了 -,-= 也要考虑被重载。在我们的合唱团例子中,由于我们可以用 += 添加一名歌手,那么我们也应该可以用 -= 删除一名歌手。
这是怎么实现的?
操作符重载是通过重写操作符的标准函数调用实现的,比如,添加合唱团成员的代码:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
val choir = Choir()
val singerMeghan = Singer("Meghan")
choir += singerMeghan
如果我们看一下反编译的 Java 代码,可以看到它是如何工作的:
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
Choir choir = new Choir();
Singer singerMeghan = new Singer("Meghan");
choir.plusAssign(singerMeghan);
编译器只是简单的通过正常的成员函数调用替换了 +=。
总结
确保您使用了operator 关键字,否则 Kotlin 会将函数视为一个普通函数来对待,并且代码也将编译失败; 检查操作符重载是否使代码更加易读; 仔细思考哪些操作符的重载对类型来说更有意义。
推荐阅读