Kotlin中的Iterator与护士小姐姐

Kotlin中的Iterator与护士小姐姐
文章图片
Screen Shot 2020-12-12 at 11.53.12 PM.png 隐喻:护士小姐姐和医生 Kotlin中的Iterator与护士小姐姐
文章图片
分诊 Iterator如同一个护士小姐姐。
护士小姐姐在诊室外组织病人们排队。
病人们怎么排序?
挂号的顺序、递交病历本的顺序还是颜值,
护士小姐姐说了算。
Iterator的调用者如同医生。
医生坐在诊室里面,专心致志的给她面前的病人看病。
看完之后只需要喊一声:“下一个”。
接下来我们一起看看Iterator是怎么做的。
从一个优雅的例子开始 Kotlin官方文档中有个例子Iterators,简洁优雅。

class Animal(val name: String)class Zoo(val animals: List) {operator fun iterator(): Iterator {// 1 return animals.iterator()// 2 } }fun main() {val zoo = Zoo(listOf(Animal("zebra"), Animal("lion")))for (animal in zoo) {// 3 println("Watch out, it's a ${animal.name}") }}

透过它我们来看看Iterator的优点。
它将数据结构封装在类的内部,调用者无需关心数据是如何存储的。
并且有迭代器的类可以使用for in循环访问,这使得代码非常接近自然语言,易读而便于维护。
简约的文档并不能使我感到满足 官网中例子对应的英文文档相当的简约,即便如此,所谓的kotlin中文网也没有对应的译文。我只好手动翻译:
迭代器 在你的类中,你能通过实现iterator操作符来定义你自己的迭代器。 ...此处省略刚才举过的例子代码十几行... 1. 在类中定义一个迭代器。它必须命名为iterator,并且被关键字operator修饰。 2. 返回的迭代器,需包括下列成员函数 · next(): Animal · hasNext(): Boolean 3. 使用自定义迭代器循环遍历动物园中的动物 迭代器可以用扩展函数的形式声明。

例子中的迭代器相当简单,仅仅是把自己的list成员的iterator透传出来。如果有特殊需求怎么办呢?
经过摸索发现我们需要定义自己的Iterator类。
大体思路: 如果当前数据中没有合适的iterator,就自己定义一个内部类xxIterator,
这个内部类,可以访问到外部类的所有数据,
这个内部类,可以将遍历外部数据相关的逻辑和遍历状态封装起来。
这个内部类,符合Iterator接口规范(实现next和hasNext函数)
最后将这个内部类通过外部类的iterator接口提供给外面用。
关键代码如下:
class Hospital(val femalePatients: List, val malePatients: List) {inner class PatientIterator : Iterator { //... public override operator fun next(): Patient { //... }public override operator fun hasNext(): Boolean { //... } }operator fun iterator(): Iterator = PatientIterator() }

需要注意的细节:
  1. Kotlin中内嵌类需要 inner修饰
  2. 重载成员需要用override修饰
  3. next、hasNext和iterator 需要用operator修饰
完整代码:
package top.ovo.hospital// 基类病人 open class Patient(val name: String) { open fun name(): String { return name } }// 男病人 class MalePatient(name: String) : Patient(name) { override fun name(): String { return "$name\t♂" } }// 女病人 class FemalePatient(name: String) : Patient(name) { override fun name(): String { return "$name\t♀" } }// 医院 class Hospital(val femalePatients: List, val malePatients: List) {inner class PatientIterator : Iterator【Kotlin中的Iterator与护士小姐姐】 { private var femalePatientsIndex: Int = 0 private var malePatientsIndex: Int = 0public override operator fun next(): Patient {if (femalePatientsIndex

代码说明: 首先我们声明一个基类“Patient”有共同的属性“name”。
然后按照性别派生了MalePatient和FemalePatient,name()方法中提供了个性化的返回。
“Hospital”类中包含两个队列,malePatients和femalePatients
内嵌类“PatientIterator”中封装了对两个病人列表的遍历逻辑:
先遍历女病人列表,然后遍历男病人列表。
如果都遍历完则通过hasNext返回没有病人了
“Hospital”中iterator()函数创建并返回了PatientIterator的实例
最后的main函数中我们使用forIn语句循环hospital实例得到队列中的每个病人。
运行结果:
$~/.sdkman/candidates/kotlin/current/bin/kotlinc hospital.kt -include-runtime -d hospital.jar && java -jar hospital.jar --- 这里是分诊台 --- 赵丽影♀正在排队 关晓童♀正在排队 杨蜜♀正在排队 柳颜♀正在排队 马匀♂正在排队 张一明♂正在排队 马化疼♂正在排队 李彦红♂正在排队

    推荐阅读