操作符
Kotlin 语言设计中有一个核心概念叫 “约定 (Conventions)”。与 C++ 或 Scala 允许定义任意符号的操作符不同,Kotlin 采用了一种更克制的方式:语言保留特定的符号(如 +, *, []),但允许你通过定义特定名称的函数(如 plus, times, get )来重载这些符号的行为。
只要函数标记为 operator 且名称匹配,编译器就会自动应用这些约定。
算术与比较操作符
这是最基础的重载,允许自定义类型参与数学运算。
| 符号 | 对应的 operator 函数 | 翻译逻辑 |
|---|---|---|
a + b | plus | a.plus(b) |
a - b | minus | a.minus(b) |
a * b | times | a.times(b) |
a / b | `div" | a.div(b) |
a % b | rem | a.rem(b) |
a..b | rangeTo | a.rangeTo(b) |
a in b | contains | b.contains(a) (注意主客体反转) |
kotlin
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}
val p = Point(1, 1) + Point(2, 2) // Point(3, 3)比较操作符
==对应equals(注意:equals是 Any 的成员,重写时无需operator,只需override)。>/<对应compareTo(需实现Comparable接口)。
索引访问操作符 (Indexed Access)
这允许对象像数组或 Map 一样使用方括号 [] 进行读写。
- 读取
a[i]对应a.get(i) - 写入
a[i] = b对应a.set(i, b)
kotlin
class Matrix(val rows: Int, val cols: Int) {
private val data = IntArray(rows * cols)
operator fun get(r: Int, c: Int): Int = data[r * cols + c]
operator fun set(r: Int, c: Int, v: Int) {
data[r * cols + c] = v
}
}
val m = Matrix(3, 3)
m[1, 1] = 5 // 调用 m.set(1, 1, 5)Invoke 操作符
invoke 是一个非常特殊的约定,它允许对象像函数一样被直接调用。
kotlin
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting, $name!")
}
}
val hello = Greeter("Hello")
hello("World") // 等价于 hello.invoke("World")应用场景
invoke 常用于 Gradle 脚本配置、拦截器链(Interceptor Chain)或将单一职责的对象伪装成函数。
解构声明 (Destructuring Declarations)
解构声明(如 val (x, y) = point)通过 componentN 约定实现。
val (a, b) = obj- 翻译为:
val a = obj.component1()val b = obj.component2()
data class 会自动生成这些函数。对于普通类,你可以手动定义:
kotlin
class User(val name: String, val age: Int) {
operator fun component1() = name
operator fun component2() = age
}属性委托约定
属性委托 (by 关键字) 的底层也是基于操作符约定的。关于委托的详细机制与实战,请参阅 委托机制 章节。
这里仅列出其核心约定:
- 读取 (
val): 编译器查找getValue操作符。 - 写入 (
var): 编译器查找setValue操作符。
kotlin
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
...
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
...
}
}中缀表达 (Infix Notation)
infix 关键字允许省略点和括号。虽然它不需要 operator 关键字,但它也是一种语法约定。
限制条件
- 必须是成员函数或扩展函数。
- 必须只有一个参数。
- 不能有默认参数或
vararg。
kotlin
infix fun String.vs(other: String) = "$this vs $other"
// 调用
"Team A" vs "Team B"标准库中的中缀函数
to:1 to "one"(生成 Pair)until:0 until 10(生成 Range)shr/shl: 位运算
总结
Kotlin 的约定机制非常强大,它在不引入新语法的前提下,让自定义类型拥有了原生类型般的“手感”。
- 算术 ->
plus,minus... - 数组感 ->
get,set - 函数感 ->
invoke - 多返回值 ->
componentN(解构) - DSL 语义 ->
infix