Kotlinのforループで独自クラスをイテレートする方法

# 概要
Kotlinでは、規約に従った実装を行うことで言語の構文に独自のプログラムを柔軟に組み込むことができます。
この記事では、 `rangeTo` の規約によって、forループ内で独自クラスをいてレートする実装例をご紹介します。

# rangeTo と ClosedRange

Kotlin の for文は以下のように記述されますが、以下の `1..3` の部分の正体は `ClosedRange` です。

```Kotlin
for (i in 1..3) print("${i*i} ") // 1 4 9
```

Kotlinのコンパイラは `start..end` を `start.rangeTo(end)` という呼び出しに変換するので、 `start` の型に `rangeTo` 関数が適切に定義されていれば、独自のクラスを for文の中でイテレートすることができます。
適切な、とは以下のシグネチャーで、 `ClosedRange` を返却する関数です。

```Kotlin
operator fun <T: Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
```

# 実装例

以下の十二支を表す列挙型(`ChineseZodiac`)をfor文で使えるように実装します。

```Kotlin
enum class ChineseZodiac(val char: String) {
    RAT("子"), OX("丑"), TIGER("寅"), RABBIT("卯"), DRAGON("辰"), SNAKE("巳"),
    HORSE("午"), SHEEP("未"), MONKEY("申"), COCK("酉"), DOG("戌"), BOAR("亥");    
}
```

まずは、実装コードの見通しをよくするために、12を法とした加算が行えるように以下の拡張関数を定義しておきます。

```Kotlin
operator fun ChineseZodiac.plus(i: Int): ChineseZodiac {
    val ord = (this.ordinal + i) % 12
    return ChineseZodiac.values()[ord]
}
```

これも、規約に従った実装となっていて、 `plus` 関数を `ChineseZodiac` に追加することにより、`+` による演算が可能となります。

```Kotlin
println(RAT + 1) // OX
```

次に `rangeTo` を拡張関数として定義します。

```Kotlin
operator fun ChineseZodiac.rangeTo(that: ChineseZodiac) = ChineseZodiacRange(this, that)
```

`ChineseZodiacRange` の定義は以下となります。
`ChineseZodiac` を型パラメータとして、 `ClosedRange` インタフェースを実装します。

```Kotlin
class ChineseZodiacRange(override val start: ChineseZodiac,
                         override val endInclusive: ChineseZodiac): ClosedRange<ChineseZodiac>
```

forループで in演算子によって `ClosedRange` をイテレートするためには、実はもう一つ規約に沿う必要があります。それは `iterator()` メソッドで `Iterator` を返却することです。
`ChineseZodiacRange`の拡張関数として以下のように実装します。

```Kotlin
operator fun ChineseZodiacRange.iterator(): Iterator<ChineseZodiac> =
	object : Iterator<ChineseZodiac> {
        private var current = start
        override fun hasNext() = current != (endInclusive + 1)
        override fun next(): ChineseZodiac {
            val ret = current
            current = current + 1
            return ret
        }
    }
```

これで、以下のようにforループでイテレートできるようになりました。

```Kotlin
    for (e in TIGER..DRAGON) print(e.char) // 寅卯辰
    println()
    for (e in COCK..OX) print(e.char) // 酉戌亥子丑
    println()
    for (e in OX..OX) print(e.char) // 丑
    println()
```

# ソースコード
今回の実装例のコード一式です：

```Kotlin
import ChineseZodiac.*

fun main(args: Array<String>) {
    for (e in TIGER..DRAGON) print(e.char) // 寅卯辰
    println()
    for (e in COCK..OX) print(e.char) // 酉戌亥子丑
    println()
    for (e in OX..OX) print(e.char) // 丑
    println()
}

enum class ChineseZodiac(val char: String) {
    RAT("子"), OX("丑"), TIGER("寅"), RABBIT("卯"), DRAGON("辰"), SNAKE("巳"),
    HORSE("午"), SHEEP("未"), MONKEY("申"), COCK("酉"), DOG("戌"), BOAR("亥");    
}

operator fun ChineseZodiac.plus(i: Int): ChineseZodiac {
    val ord = (this.ordinal + i) % 12
    return ChineseZodiac.values()[ord]
}

operator fun ChineseZodiac.rangeTo(that: ChineseZodiac) = ChineseZodiacRange(this, that)

class ChineseZodiacRange(override val start: ChineseZodiac,
                         override val endInclusive: ChineseZodiac): ClosedRange<ChineseZodiac>

operator fun ChineseZodiacRange.iterator(): Iterator<ChineseZodiac> =
	object : Iterator<ChineseZodiac> {
        private var current = start
        override fun hasNext() = current != (endInclusive + 1)
        override fun next(): ChineseZodiac {
            val ret = current
            current = current + 1
            return ret
        }
    }
```