# 淺談 Go Iterator

Go 1.23 引入了原生的 Iterator 支援，這是 Go 語言在函數式程式設計道路上的重要里程碑。這篇將分享 Go Iterator 的設計理念、使用方法和實踐。

# 什麼是 Iterator？

**Iterator**（迭代器）是一個\*\*函數\*\*，它將序列中的連續元素傳遞給 callback 函數（通常命名為 `yield`）。當序列結束或 yield 返回 false 時，函數會停止迭代。

在 Go 1.23 中，Iterator 是語言的原生特性，介面定義在 [`iter` 套件](https://pkg.go.dev/iter#Seq)中。

## Iterator 的核心設計

### 類型定義

Go 定義了兩種主要的 Iterator 類型：

```go
type Seq[V any] func(yield func(V) bool)
type Seq2[K, V any] func(yield func(K, V) bool)
```

### yield 函數的語意設計

yield 函數的核心語意是："產出並詢問是否繼續"

```mermaid
graph TD
    A[Iterator 開始] --> B[計算/獲取下一個值]
    B --> C[調用 yield value]
    C --> D{yield 返回值}
    D -->|true| E[繼續迭代]
    D -->|false| F[停止迭代]
    E --> B
    F --> G[Iterator 結束]
```

```go
// yield 函數返回值的意義：
// - true: 繼續迭代下一個元素
// - false: 停止迭代
func myIterator() iter.Seq[int] {
    return func(yield func(int) bool) {
        for i := 1; i <= 5; i++ {
            if !yield(i) { // 產出值並詢問是否繼續
                return // 尊重消費者的決定
            }
        }
    }
}
```

### 協作式控制流

Iterator 的設計體現了生產者和消費者之間的協作關係：

#### 生產者視角的語意

```go
func fibonacci() iter.Seq[int] {
    return func(yield func(int) bool) {
        a, b := 0, 1
        for {
            // 語意："我計算出了一個值，你要嗎？"
            if !yield(a) {
                // 語意："好的，你不要了，我停止生產"
                return
            }
            // 語意："你還要，我繼續計算下一個"
            a, b = b, a+b
        }
    }
}
```

#### 消費者視角的語意

```go
// range 迴圈的隱含語意
for value := range fibonacci() {
    fmt.Println(value)
    if value > 100 {
        // 隱含語意："我不需要更多了"
        break // 這會讓 yield 返回 false
    }
    // 隱含語意："我處理完了，請給我下一個"
}
```

```mermaid
sequenceDiagram
    participant P as 生產者 (Iterator)
    participant C as 消費者 (range loop)
    
    P->>C: yield(value1) - "我有一個值，你要嗎？"
    C->>P: return true - "要，請繼續"
    P->>C: yield(value2) - "下一個值"
    C->>P: return true - "繼續"
    P->>C: yield(value3) - "又一個值"
    C->>P: return false - "夠了，停止吧"
    P->>P: return - "好的，我停止"
```

## 基本使用方法

### 1\. 簡單的數值範圍迭代器

```go
package main

import (
    "fmt"
    "iter"
)

// 整數範圍迭代器
func rangeSeq(start, end int) iter.Seq[int] {
    return func(yield func(int) bool) {
        for i := start; i <= end; i++ {
            if !yield(i) {
                return
            }
        }
    }
}

func main() {
    // 使用 range 語法遍歷
    for num := range rangeSeq(1, 5) {
        fmt.Println(num) // 輸出: 1, 2, 3, 4, 5
    }
}
```

**實際用途：**

* 測試資料生成：快速生成測試用的數字序列
    
* 分頁處理：生成頁碼序列
    

### 2\. Key-Value Pair 迭代器

```go
// Map 迭代器
func mapSeq[K comparable, V any](m map[K]V) iter.Seq2[K, V] {
    return func(yield func(K, V) bool) {
        for k, v := range m {
            if !yield(k, v) {
                return
            }
        }
    }
}

// 使用
data := map[string]int{"apple": 5, "banana": 3, "cherry": 8}
for key, value := range mapSeq(data) {
    fmt.Printf("%s: %d\n", key, value)
}
```

**實際用途：**

* 配置處理：遍歷配置項目
    
* 資料轉換：將 map 轉換為其他格式
    
* 條件過濾：在遍歷過程中進行篩選
    

### 3\. 集合類型的 Iterator

```go
type Set[V comparable] struct {
    items map[V]struct{}
}

// 按照命名慣例，集合的迭代器方法命名為 All
func (s *Set[V]) All() iter.Seq[V] {
    return func(yield func(V) bool) {
        for item := range s.items {
            if !yield(item) {
                return
            }
        }
    }
}

// 使用
set := &Set[string]{items: map[string]struct{}{
    "apple": {}, "banana": {}, "cherry": {},
}}

for item := range set.All() {
    fmt.Println(item)
}
```

## 進階應用

### 1\. Pull 函數 - 手動控制迭代

```mermaid
graph LR
    A[Push Iterator<br/>seq] --> B[iter.Pull]
    B --> C[next function]
    B --> D[stop function]
    C --> E[手動拉取值]
    D --> F[清理資源]
```

```go
func demonstratePull() {
    seq := rangeSeq(1, 5)
    
    // 轉換為 Pull 迭代器
    next, stop := iter.Pull(seq)
    defer stop() // 重要：必須調用 stop 來清理資源
    
    // 手動拉取值
    for {
        value, ok := next()
        if !ok {
            break // 序列結束
        }
        fmt.Printf("Pulled: %d\n", value)
        
        // 可以在這裡添加複雜的邏輯
        if value == 3 {
            fmt.Println("Stopping early")
            break
        }
    }
}
```

**實際用途：**

* API 分頁處理：需要根據回應決定是否繼續
    
* 資料庫批次讀取：根據記憶體使用量控制讀取
    
* 檔案處理：逐行處理大檔案，可隨時停止
    

### 2\. 配對迭代器

```go
// 將序列中的值配對
func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] {
    return func(yield func(V, V) bool) {
        next, stop := iter.Pull(seq)
        defer stop()
        
        for {
            v1, ok1 := next()
            if !ok1 {
                return
            }
            
            v2, ok2 := next()
            // 如果 ok2 為 false，v2 是零值；產生最後一對
            if !yield(v1, v2) {
                return
            }
            
            if !ok2 {
                return
            }
        }
    }
}

// 使用範例：座標處理
coordinates := []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}
coordSeq := SliceSeq(coordinates)

for x, y := range Pairs(coordSeq) {
    point := Point{X: x, Y: y}
    drawPoint(point)
}
// 結果：(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)
```

### 3\. Filter 和 Map 操作

```go
// Filter 迭代器
func Filter[V any](seq iter.Seq[V], predicate func(V) bool) iter.Seq[V] {
    return func(yield func(V) bool) {
        for value := range seq {
            if predicate(value) {
                if !yield(value) {
                    return
                }
            }
        }
    }
}

// Map 迭代器
func Map[T, U any](seq iter.Seq[T], mapper func(T) U) iter.Seq[U] {
    return func(yield func(U) bool) {
        for value := range seq {
            if !yield(mapper(value)) {
                return
            }
        }
    }
}

// 鏈式操作
numbers := rangeSeq(1, 10)
evenNumbers := Filter(numbers, func(n int) bool { return n%2 == 0 })
squares := Map(evenNumbers, func(n int) int { return n * n })

for square := range squares {
    fmt.Printf("%d ", square) // 4 16 36 64 100
}
```

```mermaid
graph LR
    A[原始序列<br/>1,2,3,4,5,6,7,8,9,10] --> B[Filter<br/>偶數過濾]
    B --> C[過濾結果<br/>2,4,6,8,10]
    C --> D[Map<br/>平方轉換]
    D --> E[最終結果<br/>4,16,36,64,100]
```

### 4\. 無限序列

```go
// 費波那契數列
func Fibonacci() iter.Seq[int] {
    return func(yield func(int) bool) {
        a, b := 0, 1
        for {
            if !yield(a) {
                return
            }
            a, b = b, a+b
        }
    }
}

// 使用時需要手動控制停止
func useFibonacci() {
    for num := range Fibonacci() {
        if num > 1000 {
            break
        }
        fmt.Println(num)
    }
}

// 產生唯一 ID
func UniqueIDs() iter.Seq[string] {
    return func(yield func(string) bool) {
        counter := 0
        for {
            id := fmt.Sprintf("ID_%d_%d", time.Now().Unix(), counter)
            if !yield(id) {
                return
            }
            counter++
        }
    }
}
```

**實際用途：**

* 測試資料：生成無限測試資料
    
* 演算法實現：實現需要無限序列的演算法
    

### 5\. 批次處理

```go
// 將序列分批處理
func Batch[T any](seq iter.Seq[T], size int) iter.Seq[[]T] {
    return func(yield func([]T) bool) {
        batch := make([]T, 0, size)
        
        for item := range seq {
            batch = append(batch, item)
            if len(batch) == size {
                if !yield(batch) {
                    return
                }
                batch = batch[:0] // 重用 slice
            }
        }
        
        // 處理剩餘元素
        if len(batch) > 0 {
            yield(batch)
        }
    }
}
```

```mermaid
graph LR
    A[原始序列<br/>1,2,3,4,5,6,7,8,9] --> B[Batch size=3]
    B --> C[批次1<br/>1,2,3]
    B --> D[批次2<br/>4,5,6]
    B --> E[批次3<br/>7,8,9]
```

6. ### 常用輔助函數
    

```go
// 將 slice 轉換為 Iterator
func SliceSeq[T any](slice []T) iter.Seq[T] {
    return func(yield func(T) bool) {
        for _, item := range slice {
            if !yield(item) {
                return
            }
        }
    }
}

// 將 Iterator 收集為 slice
func Collect[T any](seq iter.Seq[T]) []T {
    var result []T
    for item := range seq {
        result = append(result, item)
    }
    return result
}

// 取前 n 個元素
func Take[T any](seq iter.Seq[T], n int) iter.Seq[T] {
    return func(yield func(T) bool) {
        count := 0
        for item := range seq {
            if count >= n {
                return
            }
            if !yield(item) {
                return
            }
            count++
        }
    }
}

// 跳過前 n 個元素
func Skip[T any](seq iter.Seq[T], n int) iter.Seq[T] {
    return func(yield func(T) bool) {
        count := 0
        for item := range seq {
            if count < n {
                count++
                continue
            }
            if !yield(item) {
                return
            }
        }
    }
}
```

## 命名慣例

根據官方文件，Iterator 的命名有以下慣例：

### 1\. 集合迭代器

```go
// 集合類型的主要迭代器命名為 All
func (s *Set[V]) All() iter.Seq[V] { ... }

// 多種序列時，名稱指示具體序列
func (c *Country) Cities() iter.Seq[*City] { ... }
func (c *Country) Languages() iter.Seq[string] { ... }
```

### 2\. 配置參數的迭代器

```go
// 需要額外配置的迭代器
func (m *Map[K, V]) Scan(min, max K) iter.Seq2[K, V] { ... }
func Split(s, sep string) iter.Seq[string] { ... }
```

### 3\. 不同順序的迭代器

```go
// 指示遍歷順序
func (l *List[V]) All() iter.Seq[V] { ... }        // 從頭到尾
func (l *List[V]) Backward() iter.Seq[V] { ... }   // 從尾到頭
func Preorder(root Node) iter.Seq[Node] { ... }    // 前序遍歷
```

## 性能考量

### 延遲求值的優勢

```go
// 延遲求值範例：只計算需要的部分
func expensiveComputation() iter.Seq[int] {
    return func(yield func(int) bool) {
        for i := 1; i <= 1000000; i++ {
            // 昂貴的計算
            result := complexCalculation(i)
            if !yield(result) {
                return // 可以提早停止，節省計算
            }
        }
    }
}

// 只取前 5 個結果，剩下的不會計算
results := Take(expensiveComputation(), 5)
for result := range results {
    fmt.Println(result)
}
```

```mermaid
graph TD
    A[開始計算] --> B{需要更多結果？}
    B -->|是| C[計算下一個]
    B -->|否| D[停止計算<br/>節省資源]
    C --> E[yield 結果]
    E --> F{消費者要繼續？}
    F -->|是| B
    F -->|否| D
```

### 記憶體使用效率

```go

// 傳統方式：需要將所有結果載入記憶體
func processAllAtOnce() []ProcessedData {
    data := loadLargeDataset() // 可能很大
    var results []ProcessedData
    for _, item := range data {
        results = append(results, process(item))
    }
    return results // 記憶體使用量可以說"翻倍"
}

// Iterator 方式：串流處理
// 用到哪，拉取到哪
func processStream() iter.Seq[ProcessedData] {
    return func(yield func(ProcessedData) bool) {
        for item := range loadDataStream() {
            processed := process(item)
            if !yield(processed) {
                return
            }
        }
    }
}
```

## 推薦的錯誤處理方式

```go
// 方法 1：使用 Result 類型
type Result[T any] struct {
    Value T
    Error error
}

func ProcessWithErrors[T, U any](seq iter.Seq[T], processor func(T) (U, error)) iter.Seq[Result[U]] {
    return func(yield func(Result[U]) bool) {
        for item := range seq {
            value, err := processor(item)
            if !yield(Result[U]{Value: value, Error: err}) {
                return
            }
        }
    }
}

// 方法 2：分離錯誤處理
func ProcessSafe[T, U any](seq iter.Seq[T], processor func(T) (U, error)) (iter.Seq[U], error) {
    var firstError error
    
    filtered := func(yield func(U) bool) {
        for item := range seq {
            value, err := processor(item)
            if err != nil {
                if firstError == nil {
                    firstError = err
                }
                continue
            }
            if !yield(value) {
                return
            }
        }
    }
    
    return filtered, firstError
}
```

## 與傳統 Iterator Pattern 的比較

### 相同點

* 目的相同：提供統一的方式遍歷集合
    
* 封裝性：隱藏集合內部實現
    
* 順序訪問：按順序訪問元素
    

### 主要差異

| 特性 | 傳統 Iterator Pattern | Go Iterator |
| --- | --- | --- |
| 實現方式 | 物件導向（介面 + 類別） | 函數式（closure + yield） |
| 狀態管理 | Iterator 物件維護狀態 | closure 維護狀態 |
| 語法支援 | 手動調用 Next(), HasNext() | 原生 range 語法 |
| 記憶體開銷 | 需要創建 Iterator 物件 | 只有函數調用開銷 |
| 組合性 | 較難組合多個迭代器 | 容易組合和鏈接 |
| 類型安全 | 依賴語言的泛型支援 | 完整的泛型支援 |

### 傳統 Iterator Pattern

```go
// 傳統方式
type Iterator[T any] interface {
    HasNext() bool
    Next() T
}

type SliceIterator[T any] struct {
    slice []T
    index int
}

func (it *SliceIterator[T]) HasNext() bool {
    return it.index < len(it.slice)
}

func (it *SliceIterator[T]) Next() T {
    if it.HasNext() {
        value := it.slice[it.index]
        it.index++
        return value
    }
    var zero T
    return zero
}

// 使用
func useTraditionalIterator() {
    data := []int{1, 2, 3, 4, 5}
    iterator := &SliceIterator[int]{slice: data}
    
    for iterator.HasNext() {
        fmt.Println(iterator.Next())
    }
}
```

### Go Iterator

```go
func SliceSeq[T any](slice []T) iter.Seq[T] {
    return func(yield func(T) bool) {
        for _, item := range slice {
            if !yield(item) {
                return
            }
        }
    }
}

// 使用
func useGoIterator() {
    data := []int{1, 2, 3, 4, 5}
    
    for item := range SliceSeq(data) {
        fmt.Println(item)
    }
}
```

```mermaid
graph TD
    subgraph "傳統 Iterator Pattern"
        A[Iterator 介面] --> B[HasNext 方法]
        A --> C[Next 方法]
        B --> D[手動控制迴圈]
        C --> D
    end
    
    subgraph "Go Iterator"
        E[iter.Seq 函數] --> F[yield 函數]
        F --> G[原生 range 語法]
        G --> H[自動控制流程]
    end
```

## Go 標準庫中已經實現的 Iterator

除了下述的 database Next()、[filepath.Walk(Dir)](https://pkg.go.dev/path/filepath#Walk)、[sync Map Range()](https://pkg.go.dev/sync#Map.Range)。其實更早之前都已經提供了 Iterator 的自我實現，也不難發現現有的 iterator 設計跟使用方式都不相同，所以 Go 才想統一標準。

## Go database 的 Next()

Go 資料庫的 [`Next()`](https://cs.opensource.google/go/go/+/refs/tags/go1.25.1:src/database/sql/sql.go;l=3023) 實現了與 Iterator 相同的迭代模式和控制流語義。

### [rows.Next](http://rows.Next)() 的實際行為

```go
// rows.Next() 的實際行為
func (rs *Rows) Next() bool {
    // 1. 釋放上一行的記憶體鎖定
    rs.closemuRUnlockIfHeldByScan()
    
    // 2. 檢查 context 是否已取消
    if rs.contextDone.Load() != nil {
        return false
    }
    
    // 3. 嘗試讀取下一行（這裡才真正從網路/磁碟讀取）
    var doClose, ok bool
    withLock(rs.closemu.RLocker(), func() {
        doClose, ok = rs.nextLocked() // 關鍵：這裡才讀取下一筆
    })
    
    // 4. 如果需要關閉就關閉
    if doClose {
        rs.Close()
    }
    
    return ok
}
```

### 實際的資料流與控制流

```go
func demonstrateActualFlow() {
    // 1. Query 只是建立連線和發送 SQL，但不等待所有結果
    rows, err := db.Query("SELECT * FROM huge_table") // 只發送查詢，不讀取資料
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    
    fmt.Println("查詢已發送，但還沒讀取任何資料")
    
    // 2. 第一次 Next() 開始從緩衝區讀取，緩衝區空時才觸發網路讀取
    if rows.Next() { // 可能觸發網路讀取，填充緩衝區
        fmt.Println("讀取到第一筆資料")
        
        var id int
        var name string
        rows.Scan(&id, &name) // 掃描剛才讀取的資料
        fmt.Printf("第一筆: %d, %s\n", id, name)
    }
    
    // 3. 每次 Next() 都會讀取下一筆
    if rows.Next() { // 通常從緩衝區直接讀取
        fmt.Println("讀取到第二筆資料")
        // ... 掃描第二筆
    }
    
    // 4. 如果我們在這裡 early break，剩下的資料不會被讀取
    fmt.Println("停止讀取，剩下的資料不會從資料庫傳輸")
}
```

```mermaid
sequenceDiagram
    participant A as 應用程式
    participant D as lib/pq驅動
    participant B as bufio緩衝區
    participant TCP as TCP連接
    participant DB as PostgreSQL
    
    A->>D: db.Query("SELECT ...")
    D->>TCP: 發送 SQL 查詢
    TCP->>DB: 傳輸查詢
    DB->>DB: 開始執行查詢
    DB->>TCP: 逐行發送 DataRow 消息
    Note over TCP: TCP將多個小消息組合成網絡包
    D->>A: 返回 rows 物件
    
    Note over A: 此時還沒讀取任何資料
    
    A->>D: rows.Next()
    D->>B: 檢查緩衝區
    Note over B: 緩衝區空，需要網絡讀取
    D->>TCP: 讀取網絡數據
    TCP->>D: 返回網路包(4-8KB，包含多行)
    D->>B: 數據存入 bufio 緩衝區
    D->>D: 從緩衝區解析第一行
    D->>A: 返回 true
    
    A->>D: rows.Scan(&data)
    D->>A: 返回掃描的資料
    
    A->>D: rows.Next()
    D->>B: 檢查緩衝區
    Note over B: 從緩衝區直接讀取第二行
    D->>D: 解析第二行數據
    D->>A: 返回 true
    
    A->>D: rows.Next()
    D->>B: 檢查緩衝區
    Note over B: 從緩衝區直接讀取第三行
    D->>A: 返回 true
    
    Note over A: 多次 Next() 都從緩衝區讀取...
    
    A->>A: break (停止迭代)
    Note over B: 緩衝區可能還有未讀數據
    Note over TCP: TCP連接上可能還有未讀包
    Note over DB: PostgreSQL可能仍在發送數據
```

### lib/pq 的實做方式

```go
func networkBehavior() {
    // PostgreSQL (lib/pq)
    rows, _ := pgDB.Query("SELECT * FROM million_rows")
    
    // lib/pq 實際行為：
    // 1. 發送查詢到 PostgreSQL
    // 2. PostgreSQL 開始執行查詢並逐行發送結果
    // 3. TCP 將多個小的 DataRow 消息組合成 package（通常4-8KB）
    // 4. lib/pq 的 bufio.Reader 緩衝這些package
    // 5. rows.Next() 從 bufio 緩衝區逐行解析，緩衝區空時才觸發網路讀取
    
    count := 0
    for rows.Next() { // 每次 Next() 會：
        // - 從 bufio 緩衝區讀取並解析一行（通常很快）
        // - 當緩衝區數據用完時，觸發網路讀取下一個package（偶爾較慢）
        // - 注意：不是應用層的批次緩存，而是網路層的被動緩衝
        
        var data string
        rows.Scan(&data)
        count++
        
        if count >= 10 {
            break // PostgreSQL 可能仍在發送資料，但客戶端停止讀取
                  // 連接上可能還有未讀的網路資料
        }
    }
}
```

# 總結

### 🎯 **核心影響**

Go 1.23 引入統一的 Iterator 標準是一個**重大的生態系統改進**，將混亂的迭代模式統一為 `iter.Seq[T]` 和 `range` 語法，帶來函數式程式設計能力和更好的資源效率。

### ✅ **主要好處**

* **統一體驗**：所有迭代都用相同的 `range` 語法
    
* **函數式能力**：支援 Map、Filter、組合等操作
    
* **性能優化**：延遲求值、恆定記憶體使用、提早退出
    
* **開發效率**：降低學習成本、提升代碼可讀性
    

### ⚠️ **現實挑戰**

* **過渡期混亂**：新舊兩套 API 並存，開發者需要同時掌握
    
* **決策負擔**：每次都要選擇用新方法還是舊方法
    
* **生態系統滯後**：標準庫和第三方庫需要時間適應
    
* **學習資源落差**：教學材料、Stack Overflow 答案新舊混雜
    

這是 Go 語言**成熟度的重要里程碑**，短期內會帶來一些混亂和學習成本，但長期來看將大幅提升 Go 的表達能力和開發體驗。關鍵是給生態系統足夠的時間來適應和標準化。

**建議**：新專案採用 Iterator，舊專案漸進式遷移，團隊內部制定統一的使用規範。
