Kotlin協(xié)程實(shí)現(xiàn)懶序列

懶序列是啥?

不使用就不初始化,調(diào)用時(shí)才加載的序列就是懶序列。kotlin中,可以利用協(xié)程的掛起和恢復(fù)特性,實(shí)現(xiàn)懶序列。

期望達(dá)到的效果

fun main() {
    val arr = generator<Int> {
        for (i in 0..5) {
            println("$i 準(zhǔn)備好啦。")
            yield(i)
        }
    }

    for (i in arr) {
        println("輸出 $i")
    }
}

// 控制臺(tái)輸出
0 準(zhǔn)備好啦。
輸出 0
1 準(zhǔn)備好啦。
輸出 1
2 準(zhǔn)備好啦。
輸出 2
3 準(zhǔn)備好啦。
輸出 3
4 準(zhǔn)備好啦。
輸出 4
5 準(zhǔn)備好啦。
輸出 5

Process finished with exit code 0

難點(diǎn)分析

  • 實(shí)現(xiàn)一個(gè)generator方法,接受一個(gè)函數(shù),并返回一個(gè)序列
  • 限定yield方法只能在generator方法的lambda表達(dá)式的作用域中使用
  • generator方法接受的函數(shù)必須是掛起函數(shù),否則無(wú)法達(dá)到懶加載的目的
  • 為了支持 foreach 表達(dá)式,需要讓generator方法返回一個(gè)Iterator對(duì)象

具體實(shí)現(xiàn)

import kotlin.coroutines.*

fun main() {
    val arr = generator<Int> {
        for (i in 0..5) {
            println("$i 準(zhǔn)備好啦。")
            yield(i)
        }
    }

    for (i in arr) {
        println("輸出 $i")
    }
}

fun <T> generator(block: suspend GeneratorScope<T>.() -> Unit): Iterator<T> {
    return GeneratorIterator(block)
}

sealed class State {
    class NotReady(val continuation: Continuation<Unit>) : State()
    class Ready<T>(val continuation: Continuation<Unit>, val nextValue: T) : State()
    object Done : State()
}

class GeneratorIterator<T>(block: suspend GeneratorScope<T>.() -> Unit) :
    Iterator<T>, GeneratorScope<T>, Continuation<Unit> {
    override val context: CoroutineContext = EmptyCoroutineContext

    private var state: State

    init {
        val startContinuation = block.createCoroutine(this, this)
        state = State.NotReady(startContinuation)
    }

    /**
     * yield方法干了啥
     * 1.掛起當(dāng)前方法,
     * 2.恢復(fù)遍歷處的方法,并將值通過(guò)狀態(tài)傳給遍歷處
     * 3.流轉(zhuǎn)狀態(tài),將狀態(tài)從 NotReady 改成 Ready
     */
    override suspend fun yield(value: T) = suspendCoroutine<Unit> {
        state = State.Ready(it, value)
    }

    /**
     * hasNext方法干了啥
     * 1.如果當(dāng)前狀態(tài)為 NotReady, 則恢復(fù)NotReady協(xié)程讓狀態(tài)進(jìn)行到 Ready 或者 Done
     * 2.然后判斷當(dāng)前state是否是Done,來(lái)確定是否還有下一個(gè)元素
     */
    override fun hasNext(): Boolean {
        if (state is State.NotReady) {
            (state as State.NotReady).continuation.resume(Unit)
        }
        return state != State.Done
    }

    /**
     * next方法干了啥
     * 1.判斷是否有下一個(gè),如果有,則取出來(lái)返回,同時(shí)流轉(zhuǎn)狀態(tài),Ready -> NotReady
     * 2.沒(méi)有就報(bào)數(shù)組越界
     */
    override fun next(): T {
        if (hasNext()) {
            val currentState = state as State.Ready<T>
            state = State.NotReady(currentState.continuation)
            return currentState.nextValue
        }
        throw IndexOutOfBoundsException("No value left.")
    }

    override fun resumeWith(result: Result<Unit>) {
        state = State.Done
    }
}

/**
 * 限制yield方法只能在特定的lambda表達(dá)式中使用
 */
interface GeneratorScope<T> {
    suspend fun yield(value: T)
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容