在Kotlin中,for循环中也可以使用in运算符,和做区间检查一样。但是在这种情况下它的含义是不同的:它被用来执行迭代。这意味着一个诸如:for(x in list) {…} 将被转换成list.iterator()的调用,然后就像在java中一样,在它上面重复调用hasNext 和 next方法,请注意,在kotlin中,这也是一种约定,这意味着iterator方法可以被定义为扩展函数。
可以为自己的类定义iterator方法,例如,可以这样定义方法来遍历日期:
上面的例子中红色方框里的意思理解起来可能会有点困难,所以做了一个详细的解说,看下面代码:
import java.time.LocalDate
//为ClosedRange<LocalDate>区间定义一个迭代器,返回的是Iterator类型
operator fun ClosedRange<LocalDate>.iterator(): Iterator<LocalDate> =
object : Iterator<LocalDate> {
//声明一个匿名对象继承Iterator
var current = start//定义一个可变变量拷贝start的值
//for循环通过此方法来判断循环是否终止
override fun hasNext() =
current <= endInclusive
//for循环通过此方法来获取区间的对象
override fun next() = current.apply {
/*apply始终返回作为实参传递给它的对象(这是重点),虽然在=号后面看上去返回的是current变量,而且current变
量的引用在apply内部也已经发生了改变,但是apply方法里面的this却没有改变,current的引用改变跟this本身没有半毛钱
关系,而这个函数的表达式最终结果是this,所以这个函数返回的并不是plusDays方法返回后的新对象,这也就做到了在修改
前返回当前日期作为结果*/
println("a ${current.hashCode()}")//等于apply方法里最终返回的this
current = plusDays(1)//plusDays=返回指定天数的 LocalDate的副本。
println("b ${current.hashCode()}")//current引用已经改变,但是引用的改变却不会影响原先所引用的对象本身
}
}
fun <T> T.apply(block: T.() -> Unit): T {//apply始终返回作为实参传递给它的对象
block()
println("c ${this?.hashCode()}")
return this
}
fun main(args: Array<String>) {
val newYear = LocalDate.ofYearDay(2017, 1)//创建一个日期:2017年的第1天
val daysOff: ClosedRange<LocalDate> = newYear.minusDays(1)..newYear//创建一个区间 ClosedRange<LocalDate>
//在for循环中将会自动调用daysOff.iterator扩展函数,然后在它上面重复调用hasNext和next方法,这是一种kotlin约定
for (dayOff in daysOff) { println(dayOff) }//迭代区间
}