简单场景描述

我们拥有一个数据类MyDate ,一个获取下一天的方法followingDate以及重写rangeTo操作符。

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

    fun followingDate(): MyDate {
        val localDate = LocalDate.of(year, month, dayOfMonth)
        val nextDay = localDate.plusDays(1)
        return MyDate(nextDay.year, nextDay.monthValue, nextDay.dayOfMonth)
    }

    operator fun rangeTo(other: MyDate): DateRange = DateRange(this, other)
}

我们想要使用for loop来遍历MyDate区间中的每一天。

fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
    for (date in firstDate..secondDate) {
        handler(date)
    }
}

那么我们的目标是:Make the class DateRange implement Iterable<MyDate>正确答案如下。

class DateRange(val start: MyDate, val end: MyDate) : Iterable<MyDate> {
    override fun iterator(): Iterator<MyDate> {
        return object : Iterator<MyDate> {
            var current: MyDate = start

            override fun hasNext(): Boolean = current <= end

            override fun next(): MyDate {
                if (!hasNext()) throw NoSuchElementException()
                val result = current
                current = current.followingDate()
                return result
            }
        }
    }
}

开始

首先,为什么需要实现 Iterable?

你想用 for 循环遍历日期范围:


kotlin
for (date in dateRange) {
// 处理每个日期
}

但是 Kotlin 怎么知道如何遍历你的 DateRange 呢?它需要知道:

  • 从哪里开始?
  • 什么时候结束?
  • 怎么获取下一个元素?

这就是 Iterable 接口的作用!

Iterable 接口要求什么?

interface Iterable<T> {
    fun iterator(): Iterator<T>
}

它只要求你提供一个 iterator() 方法,返回一个 Iterator 对象。

Iterator 是什么?

Iterator 就像一个"指针",它知道:

  • 当前位置在哪里
  • 是否还有下一个元素
  • 如何获取下一个元素
interface Iterator<T> {
    fun hasNext(): Boolean  // 还有下一个吗?
    fun next(): T          // 给我下一个!
}

为什么要 return object?

因为Iterable接口要求重写iterator()方法病缺返回一个对象Iterator<T>