在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 * b | times |
a / b | div |
a % b | mod |
a + b | plus |
a - b | minus |
我们在定义一个运算符的时候,允许两个运算对象是不同的类型,比如我们定一个运算符来把一个点放大
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