Kotlin 运算符关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的运算符重载允许您为标准运算符定义自定义行为。operator 关键字标记重载运算符的函数。本教程通过示例深入探讨了运算符重载。
基本定义
Kotlin 中的 operator 关键字用于声明重载运算符的函数。每个运算符都有一个预定义的函数名,必须使用该名称。运算符重载使代码更具可读性,并且对特定于域的操作更直观。
重载加号运算符
plus 运算符函数重载 + 运算符。您可以为您的类定义自定义的加法行为。该函数必须使用 operator 关键字标记。
package com.zetcode
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2
println(p3) // Output: Point(x=4, y=6)
}
在这里,我们为 Point 类定义了一个 plus 运算符。它将两个点的 x 和 y 坐标相加。+ 运算符现在可以与 Point 对象一起使用,使代码更直观。
重载比较运算符
可以使用 compareTo 函数重载比较运算符,如 < 和 >。此函数应返回一个负整数、零或正整数。
package com.zetcode
data class Person(val name: String, val age: Int) {
operator fun compareTo(other: Person): Int {
return age.compareTo(other.age)
}
}
fun main() {
val alice = Person("Alice", 30)
val bob = Person("Bob", 25)
println(alice > bob) // Output: true
println(alice < bob) // Output: false
}
compareTo 运算符按年龄比较 Person 对象。这使得可以使用标准比较运算符与自定义对象。该函数返回比较年龄的结果。
重载索引访问运算符
get 和 set 运算符重载索引访问运算符 []。这允许您的类表现得像一个数组或集合。
package com.zetcode class StringCollection(private val strings: List) { operator fun get(index: Int): String { return strings[index] } operator fun set(index: Int, value: String) { // Strings are immutable in List, so this is just for demo println("Setting index $index to $value") } } fun main() { val collection = StringCollection(listOf("a", "b", "c")) println(collection[1]) // Output: b collection[1] = "x" // Output: Setting index 1 to x }
在这里,我们为 StringCollection 类定义了索引访问。get 运算符检索值,而 set 运算符允许修改。请注意,在本例中,底层 List 是不可变的。
重载调用运算符
invoke 运算符允许将对象像函数一样调用。这可以使 DSL 或构建器模式更简洁易读。
package com.zetcode
class Greeter(private val greeting: String) {
operator fun invoke(name: String) {
println("$greeting, $name!")
}
}
fun main() {
val hello = Greeter("Hello")
hello("John") // Output: Hello, John!
val hi = Greeter("Hi")
hi("Sarah") // Output: Hi, Sarah!
}
Greeter 类定义了一个 invoke 运算符,该运算符接受一个名称并打印问候语。这允许像函数一样调用 Greeter 实例,使语法更自然地用于此用例。
重载一元运算符
可以使用特定的函数名称重载一元运算符,如 +、- 和 !。这些运算符对单个操作数起作用。
package com.zetcode
data class Counter(var value: Int) {
operator fun inc(): Counter {
return Counter(value + 1)
}
operator fun dec(): Counter {
return Counter(value - 1)
}
operator fun unaryMinus(): Counter {
return Counter(-value)
}
}
fun main() {
var counter = Counter(5)
println(++counter) // Output: Counter(value=6)
println(--counter) // Output: Counter(value=5)
println(-counter) // Output: Counter(value=-5)
}
Counter 类重载了递增 (inc)、递减 (dec) 和一元减 (unaryMinus) 运算符。这使得可以使用 ++、-- 和 - 与 Counter 对象。
重载复合赋值运算符
可以使用 plusAssign 函数重载复合赋值运算符,如 +=。这些运算符修改左操作数。
package com.zetcode
class ShoppingCart {
private val items = mutableListOf()
operator fun plusAssign(item: String) {
items.add(item)
}
fun showItems() {
println("Cart contains: $items")
}
}
fun main() {
val cart = ShoppingCart()
cart += "Apple"
cart += "Banana"
cart.showItems() // Output: Cart contains: [Apple, Banana]
}
ShoppingCart 类使用 plusAssign 重载了 += 运算符。这允许使用简洁的语法将项目添加到购物车。该运算符修改购物车的内部状态。
重载范围运算符
rangeTo 运算符重载 .. 运算符以创建范围。这对于创建特定于域的范围表达式很有用。
package com.zetcode
data class Date(val year: Int, val month: Int, val day: Int) {
operator fun rangeTo(other: Date): List {
val dates = mutableListOf()
var current = this
while (current <= other) {
dates.add(current)
current = current.nextDay()
}
return dates
}
private fun nextDay(): Date {
// Simplified implementation
return if (day < 28) copy(day = day + 1)
else if (month < 12) copy(month = month + 1, day = 1)
else copy(year = year + 1, month = 1, day = 1)
}
operator fun compareTo(other: Date): Int {
return when {
year != other.year -> year - other.year
month != other.month -> month - other.month
else -> day - other.day
}
}
}
fun main() {
val start = Date(2023, 1, 1)
val end = Date(2023, 1, 3)
val range = start..end
println(range) // Output: [Date(year=2023, month=1, day=1), ...]
}
此示例显示了如何使用 .. 运算符创建日期范围。rangeTo 运算符生成两个日期之间的所有日期。比较范围也需要 compareTo 运算符。
运算符重载的最佳实践
- 保持直观的行为: 运算符的行为应该与用户对类似内置类型的期望相同。
- 不要过度重载: 仅当它使代码更具可读性并且该操作是该类型的基本操作时,才重载运算符。
- 遵循数学惯例: 对于数学运算,请遵循标准的数学规则和属性。
- 记录重载的运算符: 在您的类文档中清楚地记录重载运算符的行为。
- 考虑性能: 运算符函数可能被频繁调用,因此请确保它们是高效的。
来源
本教程深入探讨了 Kotlin 的 operator 关键字,展示了如何为自定义类型重载各种运算符。我们探讨了算术、比较、索引和其他运算符类型。正确使用运算符重载可以使特定于域的代码更具表现力和可读性。
作者
列出 所有 Kotlin 教程。