用代码实例解释Kotlin操作符重载

67 阅读3分钟

在Kotlin中,类型运算符如加算术运算符(+)和减算术运算符(-)会调用一个相应的函数成员来执行预定的操作。

例如,要计算Int 类型的a + b Kotlin将调用.plus() 下的函数:

val a: Int = 5
val b: Int = 2
print(a + b) // a.plus(b) = 7

但是请注意,当你在String 类型上调用相同的+ 运算符时,操作会从计算两个数字的和变成连接字母:

val a: String = "Hello"
val b: String = " World"
print(a + b) // a.plus(b) = Hello World

这是可能的,因为像.plus() 这样的运算符函数在Kotlin中是重载的。

String 类中,plus() 函数的定义如下所示:

public operator fun plus(other: Any?): String

但是对于Int 类,定义是这样的:

public operator fun plus(other: Int): Int

这就是Kotlin中运算符重载的含义。它允许你重载那些被类型操作符调用的成员函数。

通过操作符重载,你可以定义当操作符在你的classdata class 实例上被调用时,Kotlin会做什么。

例如,假设你有一个User 类,有一个从构造函数初始化的属性,叫做name :

class User(val name: String)

让我们创建一个User 类型的对象,并调用+ 操作符来执行串联,看看会发生什么:

val user = User("Nathan")
print(user + "Mr. ")

当你运行上述代码时,Kotlin会抛出一个Unresolved reference error ,因为Kotlin不知道接收器的类型User

为了解决这个错误,你需要重载plus() 函数。

要重载一个运算符函数,你需要在fun 关键字前添加operator 修改器,如下图所示:

class User(val name: String) {
 operator fun plus(other: String): String {
 return this.name + other
 }
}
val user = User("Nathan")
print(user + " Sebhastian") // user.plus(" Sebhastian") = Nathan Sebhastian

随着plus() 函数在User 类中被重载,+ 运算符现在知道当user.plus() 被调用时应该做什么。

为什么运算符重载是有用的

操作符重载是有用的,因为它允许Kotlin操作符对你在源代码中定义的类和类型有意义。

操作符重载不只是抛出一个错误,因为它不知道如何处理你的数据类型,操作符重载允许你整合自定义定义的类型,就像它们是内置类型一样。

操作符重载派上用场的另一个例子是当你有一个涉及几何形状的自定义数据类型时。

假设你有一个Rectangle 形状,有lengthwidth 属性,如下图所示:

data class Rectangle(length: Int, width: Int)

你可以覆盖单数减法运算符- ,将lengthwidth 属性转换为它们的等效负值。

如下图所示,在你的data class 定义中添加unaryMinus() 函数:

data class Rectangle(val length: Int, val width: Int) {
 operator fun unaryMinus(): Rectangle {
 return Rectangle(-this.length, -this.width)
 }
}

请注意,unaryMinus() 是当你把减号运算符放在变量名之前时调用的函数。

如果你把减号运算符放在变量名之后,你需要重载minus() 函数。

下面是一个从Rectangle 类调用unaryMinus() 的例子:

val rec = Rectangle(8, 5)
val recMinus = -rec
println(recMinus.length) // -8
println(recMinus.width) // -5

如果没有运算符重载,你必须手动重新分配属性值。

Kotlin只允许你重载一组预先定义好的操作符。你可以参考Kotlin操作符重载文档,了解你可以重载的操作符的完整列表及其具体规则。

我希望这个教程能帮助你了解Kotlin中的运算符重载是如何工作的。🙏