[毎日Kotlin] Day15. Comparison(演算子)

2018.02.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

毎日Kotlinシリーズです。

このシリーズを初めての方はこちらです。「毎日Kotlin」はじめました | Developers.IO

問題

Comparison | Try Kotlin

演算子のオレオレルールを作れちゃいます。

Read about operator overloading to learn how different conventions for operations like ==, <, + work in Kotlin. Add the function compareTo to the class MyDate to make it comparable. After that the code below date1 < date2 will start to compile.

In Kotlin when you override a member, the modifier override is mandatory.

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    
}

fun compare(date1: MyDate, date2: MyDate) = date1 < date2

狙い

ここで考えて欲しい問題の意図はなんだろうか?

+ - * /などの演算子を自作クラスのときでも使えたら便利ですよね。

たとえば、今回のように自作日時クラスMyDateを作って、date1 < date2みたいに比較できたら、なんか美しい。

どのクラス演算子でも記述できますが、オレオレ規約になりすぎないように、直感的にわかるものだけにしましょう。

解答例

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    override fun compareTo(other: MyDate) = when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }
}

これを実現する方法としてKotlinでは、演算子を用いた場合に呼ばれるインターフェイス、メソッドが決まっています。 たとえば、< >などの比較演算子をするときは、Comparableが実装されcompareToを呼ぶということになります。

つまり、date1 < date2の等価コードは、data1.compareTo(date2)です。これはソースの可読性向上や短くかける機能です。

用法用量をお確かめの上お使いください。きわどい部分につかうと読みにくくなってしまいます。

オーバーロードできる演算子の一覧です。

Operator overloading - Kotlin Programming Language

operator

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) {
    operator fun compareTo(other: MyDate) = when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }
}

インターフェイスの実装を明確にしなくても、operatorキーワードをつけてメソッドのAPIをあわせて実装すると、よしなにやってくれます。

Keywords and Operators - Kotlin Programming Language

operator marks a function as overloading an operator or implementing a convention

拡張関数

operator fun MyDate.compareTo(other: MyDate) = when {
    year != other.year -> year - other.year
    month != other.month -> month - other.month
    else -> dayOfMonth - other.dayOfMonth
}

なんと拡張関数でも演算子の規約を実装することが出来るのです!つまり、「このライブラリ<でかけたら便利なのに」っと思ったら、拡張できちゃうんですよ!すごいですよね。もう一度いいます。すごいですよね!

便利すぎる。

用法用量をお確かめの上お使いください。きわどい部分につかうと読みにくくなってしまいます。

あとがき

Day16.でまたお会いしましょう。