【Coroutines】Implement Python Generator by Kotlin Coroutines

Expected

a generator object that can generate sequence objects

and only generate object when consumer object request for it

kotlin 复制代码
fun main() {
    val generator = generator {
        yield(100)
        yield(200)
        yield(300)
    }
    while (generator.hasNext()) {
        val value = generator.await()
        println(value)
    }
}
Implementation
kotlin 复制代码
package com.code.kotlin

import kotlin.coroutines.*

@RestrictsSuspension
interface GeneratorScope<T> {

    suspend fun yield(value: T)
}

interface GeneratorIterator<T> : Iterator<T> {

    fun await(): T
}

internal interface Generator<T> : GeneratorScope<T>, GeneratorIterator<T>, Continuation<Any>

internal sealed class GeneratorState<T> {
    class WAITING<T>(val continuation: Continuation<Unit>) : GeneratorState<T>()
    class READY<T>(val continuation: Continuation<Unit>, val value: T) : GeneratorState<T>()
    class COMPLETED<T> : GeneratorState<T>()
}

internal class GeneratorImpl<T> : Generator<T> {

    override val context: CoroutineContext = EmptyCoroutineContext

    internal lateinit var state: GeneratorState<T>

    override suspend fun yield(value: T) {
        suspendCoroutine { continuation ->
            when (val _state = state) {
                is GeneratorState.WAITING -> {
                    state = GeneratorState.READY(continuation, value)
                }
                is GeneratorState.READY,
                is GeneratorState.COMPLETED -> throw IllegalStateException()
            }
        }
    }

    override fun resumeWith(result: Result<Any>) {
        state = GeneratorState.COMPLETED()
    }

    private fun resume() {
        when (val _state = state) {
            is GeneratorState.WAITING -> {
                _state.continuation.resume(Unit)
            }
            else -> {}
        }
    }

    override fun hasNext(): Boolean {
        resume()
        return state !is GeneratorState.COMPLETED
    }

    override fun next(): T {
        when (val _state = state) {
            is GeneratorState.READY -> {
                state = GeneratorState.WAITING(_state.continuation)
                return _state.value
            }
            is GeneratorState.WAITING,
            is GeneratorState.COMPLETED -> throw IllegalStateException()
        }
    }

    override fun await() = next()
}

fun <T> generator(
    block: suspend GeneratorScope<T>.() -> Unit
): GeneratorIterator<T> {
    val generator = GeneratorImpl<T>()
    val continuation = block.createCoroutine(generator, generator)
    generator.state = GeneratorState.WAITING(continuation)
    return generator
}
相关推荐
知识分享小能手几秒前
Java学习教程,从入门到精通,Java 变量命名规则(12)
java·大数据·开发语言·python·学习·java学习·java后端开发
知识分享小能手2 分钟前
Java学习教程,从入门到精通,Java switch语句语法知识点(14)
java·开发语言·python·学习·javaee·大数据开发·java大数据
爱就是恒久忍耐13 分钟前
CANopen中错误帧的制造和观测
网络·python·制造
Elastic 中国社区官方博客27 分钟前
将你的 Kibana Dev Console 请求导出到 Python 和 JavaScript 代码
大数据·开发语言·前端·javascript·python·elasticsearch·ecmascript
声声codeGrandMaster33 分钟前
爬虫+数据保存2
爬虫·python·mysql
deephub41 分钟前
过采样与欠采样技术原理图解:基于二维数据的常见方法效果对比
人工智能·python·机器学习·采样技术
北京_宏哥1 小时前
《最新出炉》系列入门篇-Python+Playwright自动化测试-41-录制视频
前端·python·测试
waterHBO1 小时前
python 制作 发货单 (生成 html, pdf)
python·pdf·html
love_and_hope1 小时前
Pytorch学习--神经网络--线性层及其他层
人工智能·pytorch·python·深度学习·神经网络·学习·pip
彳亍2611 小时前
【Python单元测试】pytest框架单元测试 配置 命令行操作 测试报告 覆盖率
python·单元测试·pytest