Skip to content

在Java中我们只能够对基础数据类型使用算术运算符(+、-、*、/), 而在Kotlin中可以根据自己的需求对任何对象进行算术运算, 比如 BigDecimal,

val a = BigDecimal("2")
val b = BigDecimal("2")
print(a + b)

从上面的代码可以看到我们之间使用的+对两个BigDecimal进行求和, 这样比直接调用add更加直接, 同时也直接 +=.

二元算术运算

这里我们定义一个Point

data class Point(val x: Int, val y: Int)

接下来我们就看看如何实现对普通对象进行二元运算, 实现两个点相加, 在Point类中添加plus方法

data class Point(val x: Int, val y: Int) {
    operator fun plus(point: Point): Point {
        return Point(x + point.x, y + point.y)
    }
}

这里使用的关键字operator, 用来表示这个plus方法作为约定实现,不是碰巧定义了相同的方法名. 除了定义成成员函数也可以把plus定义成扩展函数. 然后来测试下我们的重载是否生效

fun main() {
    val p1 = Point(10, 20)
    val p2 = Point(10, 20)
    print(p1 + p2)
}

输出正确

Point(x=20, y=40)

Kotlin允许重载的二元算术运算符的约定函数名

表达式函数名
a * btimes
a / bdiv
a % bmod
a + bplus
a - bminus

我们在定义一个运算符的时候,允许两个运算对象是不同的类型,比如我们定一个运算符来把一个点放大

data class Point(val x: Int, val y: Int) {
    operator fun plus(point: Point): Point {
        return Point(x + point.x, y + point.y)
    }

    operator fun times(scale: Double): Point {
        return Point((x * scale).toInt(), (y * scale).toInt())
    }
}

fun main() {
    print(Point(10, 20) * 2.0)
}

Kotlin运算符不支持自动交换运算符的左右两边, 若我们需要支持2.0 * Point 需要给Double添加扩展函数

复合赋值运算符

当我们定义了plus这样的运算符函数后, 就已经支持 += 这种复合赋值操作了

var p1 = Point(10, 20)
p1 += Point(10, 20)
print(p1)

有些时候, 复合赋值运算符不会创建新的对象,直接在原对象上修改,比如集合添加元素操作

val numbers = ArrayList<Int>()
numbers += 10

除了定义 plus 函数在实现复合赋值操作, 还可以通过定义函数名 plusAssign 返回值Unit来实现复合赋值操作, 其他的二元算术运算符也有类似的名字, timesAssign minusAssign, 下面来看看集合是如何实现的 plusAssign

public inline operator fun <T> MutableCollection<in T>.plusAssign(element: T) {
    this.add(element)
}

注意: 若在代码中同时都实现了plus plusAssign, 当用到了+=的时候理论上来说都会被调用,编译器这时候会报错. 最好是不要给同一个类同时实现这两个方法. 例如上面的Point例子,这个类是不可变的就应该只提供一个返回一个新值(plus), 如果这个类是可变的,比如集合,那么应该提供plusAssign

原文链接: http://herman7z.site