kotlin sequenceOf 和 generateSequence 講解

你想深入了解 Kotlin 中創(chuàng)建 Sequence(序列)的兩個(gè)核心函數(shù):sequenceOfgenerateSequence,包括它們的區(qū)別、使用規(guī)則和實(shí)際案例,我會(huì)幫你理清這兩個(gè)函數(shù)的適用場(chǎng)景和使用方式,讓你能精準(zhǔn)選擇合適的函數(shù)創(chuàng)建序列。

一、核心概念先理清

首先明確:sequenceOfgenerateSequence 都是 Kotlin 標(biāo)準(zhǔn)庫(kù)提供的創(chuàng)建 Sequence 的頂層函數(shù),但設(shè)計(jì)目標(biāo)完全不同:

  • sequenceOf:用于創(chuàng)建有限的、已知元素的序列(靜態(tài)序列);
  • generateSequence:用于創(chuàng)建動(dòng)態(tài)生成的序列(可無(wú)限、可按需生成,核心是惰性)。

二、sequenceOf 詳解

1. 定義與規(guī)則
sequenceOf 是一個(gè)可變參數(shù)函數(shù),接收一組確定的元素,直接封裝成 Sequence。

  • 語(yǔ)法:fun <T> sequenceOf(vararg elements: T): Sequence<T>
  • 核心特點(diǎn):元素是預(yù)先確定的,序列長(zhǎng)度固定,本質(zhì)是 “把已知元素包裝成序列”。

2. 基礎(chǔ)案例

fun main() {
    // 1. 基礎(chǔ)使用:創(chuàng)建有限序列
    val numberSequence = sequenceOf(1, 2, 3, 4, 5)
    
    // 執(zhí)行操作(惰性,直到終止操作觸發(fā))
    val result = numberSequence
        .filter { it % 2 == 0 }
        .map { it * 10 }
        .toList()
    
    println(result) // 輸出:[20, 40]

    // 2. 空序列:sequenceOf() 或 emptySequence()
    val emptySeq1 = sequenceOf<Int>()
    val emptySeq2 = emptySequence<Int>()
    println(emptySeq1.count()) // 輸出:0
    println(emptySeq2.count()) // 輸出:0
}

3. 與 listOf 的對(duì)比
sequenceOf(1,2,3) 等價(jià)于 listOf(1,2,3).asSequence(),但 sequenceOf 更直接(無(wú)需先創(chuàng)建 List 再轉(zhuǎn)換):

fun main() {
    // 兩種方式等價(jià),但sequenceOf更簡(jiǎn)潔
    val seq1 = sequenceOf(1, 2, 3)
    val seq2 = listOf(1, 2, 3).asSequence()
    
    println(seq1.toList() == seq2.toList()) // 輸出:true
}

三、generateSequence 詳解

generateSequence 是創(chuàng)建動(dòng)態(tài)序列的核心函數(shù),它通過(guò) “種子值 + 生成器函數(shù)” 按需生成元素,支持無(wú)限序列(惰性的核心體現(xiàn))。
1. 兩種重載形式

函數(shù)簽名 說(shuō)明 適用場(chǎng)景
fun <T : Any> generateSequence(nextFunction: () -> T?): Sequence<T> 無(wú)初始種子,直接通過(guò)函數(shù)生成下一個(gè)元素 無(wú)初始值的動(dòng)態(tài)生成(如讀取文件行)
fun <T> generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence<T> 有初始種子,基于前一個(gè)元素生成下一個(gè) 有初始值的遞推生成(如自然數(shù)、斐波那契)

核心規(guī)則

  • 生成器函數(shù)返回 null 時(shí),序列終止;
  • 若生成器函數(shù)永遠(yuǎn)不返回 null,則生成無(wú)限序列;
  • 元素是按需生成的(直到終止操作觸發(fā),才生成需要的元素)。

2. 案例 1:有種子的有限序列

fun main() {
    // 生成從1開(kāi)始,每次+2,直到>10為止的序列
    val oddNumbers = generateSequence(1) { prev ->
        val next = prev + 2
        if (next > 10) null else next // 返回null終止序列
    }
    
    // 轉(zhuǎn)換為L(zhǎng)ist,觸發(fā)元素生成
    println(oddNumbers.toList()) // 輸出:[1, 3, 5, 7, 9]
}

3. 案例 2:無(wú)限序列(核心場(chǎng)景)
generateSequence 最強(qiáng)大的地方是支持無(wú)限序列(因?yàn)槎栊?,不?huì)一次性生成所有元素):

fun main() {
    // 生成無(wú)限自然數(shù)序列(1,2,3,...)
    val naturalNumbers = generateSequence(1) { it + 1 }
    
    // 只取前5個(gè)元素,不會(huì)生成全部無(wú)限元素
    val first5 = naturalNumbers.take(5).toList()
    println(first5) // 輸出:[1, 2, 3, 4, 5]

    // 找第一個(gè)大于100的偶數(shù)(僅生成到102就終止)
    val firstEvenOver100 = naturalNumbers
        .filter { it % 2 == 0 }
        .first { it > 100 }
    println(firstEvenOver100) // 輸出:102
}

4. 案例 3:無(wú)種子的序列(讀取動(dòng)態(tài)數(shù)據(jù))
模擬 “逐行讀取文件”(實(shí)際場(chǎng)景中,文件行是動(dòng)態(tài)的、未知長(zhǎng)度的):

fun main() {
    // 模擬文件行生成器(實(shí)際可替換為File.reader().readLine())
    var lineNumber = 0
    val fileLines = generateSequence {
        lineNumber++
        if (lineNumber > 3) null else "第${lineNumber}行內(nèi)容"
    }
    
    // 遍歷輸出(按需生成每一行)
    fileLines.forEach { println(it) }
    // 輸出:
    // 第1行內(nèi)容
    // 第2行內(nèi)容
    // 第3行內(nèi)容
}

5. 案例 4:生成斐波那契數(shù)列

fun main() {
    // 種子是Pair(前一個(gè)數(shù), 當(dāng)前數(shù)),初始為(0,1)
    val fibonacci = generateSequence(Pair(0, 1)) { (a, b) ->
        Pair(b, a + b) // 下一個(gè)數(shù)=前兩個(gè)數(shù)之和
    }.map { it.second } // 提取數(shù)列值
    
    // 取前10個(gè)斐波那契數(shù)
    val first10Fib = fibonacci.take(10).toList()
    println(first10Fib) // 輸出:[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
}

四、sequenceOf vs generateSequence 核心對(duì)比

特性 sequenceOf generateSequence
元素來(lái)源 預(yù)先確定的靜態(tài)元素 生成(種子 + 生成器函數(shù))
序列長(zhǎng)度 固定、有限 可有限(返回 null 終止)、可無(wú)限
惰性程度 低(元素已確定,僅操作惰性) 高(元素按需生成,操作也惰性)
適用場(chǎng)景 已知元素的序列(如固定列表轉(zhuǎn)序列) 動(dòng)態(tài)生成的序列(如自然數(shù)、斐波那契、讀取動(dòng)態(tài)數(shù)據(jù))

五、避坑點(diǎn)

  1. 無(wú)限序列必須加終止操作
    若用 generateSequence 創(chuàng)建無(wú)限序列,必須搭配 take()、first() 等短路操作,否則調(diào)用 toList() 會(huì)導(dǎo)致無(wú)限循環(huán) / 內(nèi)存溢出
// 錯(cuò)誤示例(無(wú)限循環(huán)):
// val allNatural = generateSequence(1) { it + 1 }.toList()

// 正確示例(加take限制):
val limited = generateSequence(1) { it + 1 }.take(100).toList()
  1. generateSequence 的種子可為 null
    若種子為 null 且生成器函數(shù)也返回 null,則序列為空:
val emptySeq = generateSequence(null) { it ?: null }
println(emptySeq.count()) // 輸出:0

總結(jié)

  1. sequenceOf:用于創(chuàng)建已知元素的有限序列,是 “靜態(tài)元素的序列包裝器”,語(yǔ)法簡(jiǎn)潔,等價(jià)于 listOf(...).asSequence()。
  2. generateSequence:用于創(chuàng)建動(dòng)態(tài)生成的序列,支持無(wú)限序列和按需生成,核心是 “種子 + 生成器函數(shù)”,是處理動(dòng)態(tài) / 無(wú)限數(shù)據(jù)的首選。
  3. 選擇原則:元素已知用 sequenceOf,元素需要?jiǎng)討B(tài)生成(如遞推、讀取動(dòng)態(tài)數(shù)據(jù))用 generateSequence
?著作權(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)容