Kotlinの演算子オーバーロード(Operator overloading)

演算子オーバーロード(Operator overloading)

Kotlinには演算子オーバーロード(Operator overloading)というものがある。既存の演算子を別の形に対しても使えるように拡張する機能である。たとえば数値を表すクラスがあるとき、そのクラスのインスタンス同士で足し算や掛け算などを行いたい場合がある。このとき、メソッド呼び出しによる書き方ではなく、演算子を使ってa + bのように書けるようにするのが演算子オーバーロードである。

演算子は特定のシグネチャを持つメソッドに対応する。+演算子は、fun plus(myInt: MyInt): MyIntのようなシグネチャのメソッドを定義することで使えるようになる。つまり、plus()minus()などの演算子メソッドを定義することで、+-などの演算子を定義できる。

具体例を見ながら分かりやすく説明するために、次のようにMyIntクラスを定義する。Int値を1つだけ持つ簡単なクラスである。

例: plusメソッドが定義されたMyIntクラス

class MyInt(val value: Int) {
    fun plus(myInt: MyInt): MyInt =
         MyInt(value + myInt.value)
}

plusメソッドを使うと、自分自身と別のMyIntオブジェクトを足すことができる。そして、このplusメソッドによって+演算子を使えるようになる。

例: +演算子を使用できる

// 通常のメソッド呼び出しによる書き方
val sum = MyInt(3).plus(MyInt(5))
println(sum.value) // => 8

// 演算子を使った書き方
val sum2 = MyInt(2) + MyInt(7)
println(sum2.value) // => 9

演算子拡張関数

次はもう1つの興味深い例である。演算子に対応するメソッドは拡張関数として定義することもできる。下では、拡張関数としてStringBuilderplusAssignメソッドを追加している。このplusAssignメソッドは+=演算子に対応する。

例: +=演算子に対応する拡張関数

fun StringBuilder.plusAssign(any: Any) {
  append(any)
}

Listing 29 +=演算子を使用できる

val sb = StringBuilder()
sb += "I"
sb += " am"
sb += " Taro"
println(sb) // => I am Taro

その他の演算子とそのメソッドシグネチャ

演算子と演算子メソッドのシグネチャは次のとおりである。

a + b          a.plus(b)
a - b          a.minus(b)
a * b          a.times(b)
a / b          a.div(b)
a % b          a.rem(b)  // mod()からrem()に変更
a += b         a.plusAssign(b)
a -= b         a.minusAssign(b)
a *= b         a.timesAssign(b)
a /= b         a.divAssign(b)
a %= b         a.modAssign(b)
+a             a.unaryPlus()
-a             a.unaryMinus()
!a             a.not()
++a            a.inc()
--a            a.dec()
a == b         a?.equals(b) ?: (b === null)
a != b         !(a?.equals(b) ?: (b === null))
a < b          a.compareTo(b) > 0
a > b          a.compareTo(b) < 0
a <= b         a.compareTo(b) >= 0
a >= b         a.compareTo(b) <= 0
!var           a.not()
a..b           a.rangeTo(b)
a in b         a.contains(b)
a !in b        !a.contains(b)
a[i]           a.get(i)
a[i, j]        a.get(i, j)
a[i] = b       a.set(i, b)
a[i, j] = b    a.set(i, j, b)
a()            a.invoke()
a(i)           a.invoke(i)
a(i, j)        a.invoke(i, j)

参考