Kotlin迭代器的使用

Iterator and Iterable interface in kotlin

以前一直不理解Iterable与Iteration的关系,在kotlin的语法里面,正好可以区别开。iterable是一个接口,需要一个函数实现它,并实现它的iterator方法,返回一个真正的iterator类。具体的迭代应该怎么做,需要传一个继承iterator接口的类。

示例:

1
data class MyDate(val year: Int,val month: Int,val dayOfMonth: Int)

需要注意的是,在实现迭代之前,需要实现comparable接口,这样可以使用<,<=,>,>=这四个逻辑运算。

如下

1
2
3
4
5
6
7
8
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中,需要使用到迭代的地方一般是range函数中,所以,现在假设使用for循环迭代日期;

1
2
3
for (date in firstDate..secondDate) {
handler(date)
}

现在,语法糖部分..也就是rangeTo()部分没有实现。rangeTo这个内联函数很有意思,它接收一个MyDate类,作为end,因为上文中实现了比较,所以可以知道迭代的对象是否再range的闭区间(与大多数语言不同,kotlin中的)rangTo函数实现的是左右闭区间的范围,和一般的左闭右开的区间范围很不同。如果需要用到左闭右开区间,可以使用until语法糖。那么直接重载rangTo方法,让其返回一个继承iterable<T>接口的类。

1
operator fun MyDate.rangeTo(other: MyDate) = DateRange(this, other)//return iterabler<MyDate>

那么接下来的需要实现这个继承iterable接口的类

1
2
3
class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate>{
override fun iterator(): Iterator<MyDate> = DateIterator(this)
}

最后实现继承iterator的类就好了,需要实现next(),hasNext()基本方法

1
2
3
4
5
6
7
8
9
class DateIterator(val dateRange:DateRange) : Iterator<MyDate> {
var current: MyDate = dateRange.start
override fun next(): MyDate {
val result = current
current = current.nextDay()
return result
}
override fun hasNext(): Boolean = current <= dateRange.end
}
总结

iterator和iterable接口是逻辑上是比较绕的,但是却能很好的将不同功能面的逻辑抽象分离出来,高内聚低耦合,很厉害。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!