Go 1.24迭代器進階:range over func深度實戰 2026

编程语言

Go 1.24迭代器進階:range over func深度實戰

Go 1.22引入了range over int,Go 1.23引入了range over func——Go終於有了「一等公民」的迭代器。但很多Gopher還停留在for i, v := range slice的階段,對range over func的理解僅限於標準庫的slicesmaps包。

到了Go 1.24,迭代器生態已經成熟:泛型迭代器、迭代器組合、懶求值管道……這些模式可以讓你的Go程式碼更優雅、更高效、更Go-idiomatic。本文從5個核心模式出發,帶你徹底掌握Go迭代器。

核心概念速覽

概念 說明 簽名
迭代器函式(Iterator Function) 可被range遍歷的函式型別 func(yield func(V) bool)
帶索引迭代器 同時回傳索引和值 func(yield func(int, V) bool)
Pull迭代器 手動拉取下一個值 func() (V, bool)
Push迭代器 推送值給yield回呼 func(yield func(V) bool)
迭代器組合 多個迭代器串聯/並聯 func(...Iter) Iter
懶求值 延遲到實際消費時才計算 迭代器天然懶求值

Go迭代器的5大痛點

  1. 自訂集合遍歷繁瑣:樹、圖、鏈結串列等結構需要手寫遍歷回呼,程式碼醜陋
  2. 管道式資料處理缺失:無法像Python生成器那樣鏈式filter/map
  3. 泛型迭代器型別複雜func(yield func(V) bool)的簽名讓初學者頭痛
  4. 迭代器與goroutine互動:併發迭代器的正確使用姿勢不清晰
  5. Pull vs Push選擇困難:兩種迭代器模式何時用哪種不明確

模式一:range over func基礎

Go 1.23引入的三種迭代器函式簽名,是理解一切的基礎。

// go-iterator-basics/main.go
// 執行環境: Go 1.24+ / 無額外依賴
package main

import (
	"fmt"
	"iter"
)

// Range 生成整數序列迭代器
func Range(n int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := range n {
			if !yield(i) {
				return
			}
		}
	}
}

// RangeWithStep 生成帶步長的整數序列
func RangeWithStep(start, end, step int) iter.Seq[int] {
	return func(yield func(int) bool) {
		for i := start; i < end; i += step {
			if !yield(i) {
				return
			}
		}
	}
}

// Enumerate 為任意切片新增索引
func Enumerate[T any](items []T) iter.Seq2[int, T] {
	return func(yield func(int, T) bool) {
		for i, item := range items {
			if !yield(i, item) {
				return
			}
		}
	}
}

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

// ToPull 將Push迭代器轉換為Pull迭代器
func ToPull[T any](seq iter.Seq[T]) func() (T, bool) {
	next, stop := iter.Pull(seq)
	return func() (T, bool) {
		v, ok := next()
		return v, ok
	}
}

func main() {
	fmt.Println("=== 基本迭代器 ===")
	for i := range Range(5) {
		fmt.Print(i, " ") // 0 1 2 3 4
	}
	fmt.Println()

	fmt.Println("=== 帶步長 ===")
	for i := range RangeWithStep(0, 20, 5) {
		fmt.Print(i, " ") // 0 5 10 15
	}
	fmt.Println()

	fmt.Println("=== 帶索引 ===")
	fruits := []string{"蘋果", "香蕉", "橘子"}
	for i, fruit := range Enumerate(fruits) {
		fmt.Printf("%d: %s  ", i, fruit)
	}
	fmt.Println()

	fmt.Println("=== 提前退出 ===")
	for v := range Take(3, Range(100)) {
		fmt.Print(v, " ") // 0 1 2
	}
	fmt.Println()

	fmt.Println("=== Pull迭代器 ===")
	pull := ToPull(Range(3))
	for {
		v, ok := pull()
		if !ok {
			break
		}
		fmt.Print(v, " ") // 0 1 2
	}
	fmt.Println()
}

模式二:泛型迭代器

泛型讓迭代器成為真正的「一等公民」——一個Filter函式可以過濾任何型別的序列。

// go-generic-iterator/main.go
// 執行環境: Go 1.24+ / 無額外依賴
package main

import (
	"fmt"
	"iter"
	"strings"
)

// Filter 過濾序列中的元素
func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if predicate(v) {
				if !yield(v) {
					return
				}
			}
		}
	}
}

// Map 對序列中的每個元素進行變換
func Map[T any, R any](seq iter.Seq[T], transform func(T) R) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq {
			if !yield(transform(v)) {
				return
			}
		}
	}
}

// FlatMap 對每個元素變換後展平
func FlatMap[T any, R any](seq iter.Seq[T], transform func(T) iter.Seq[R]) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq {
			for r := range transform(v) {
				if !yield(r) {
					return
				}
			}
		}
	}
}

// Reduce 將序列歸約為單個值
func Reduce[T any, R any](seq iter.Seq[T], initial R, accumulator func(R, T) R) R {
	result := initial
	for v := range seq {
		result = accumulator(result, v)
	}
	return result
}

// Chunk 將序列分塊
func Chunk[T any](size int, seq iter.Seq[T]) iter.Seq[[]T] {
	return func(yield func([]T) bool) {
		chunk := make([]T, 0, size)
		for v := range seq {
			chunk = append(chunk, v)
			if len(chunk) == size {
				if !yield(chunk) {
					return
				}
				chunk = make([]T, 0, size)
			}
		}
		if len(chunk) > 0 {
			yield(chunk)
		}
	}
}

// Distinct 去重
func Distinct[T comparable](seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		seen := make(map[T]bool)
		for v := range seq {
			if !seen[v] {
				seen[v] = true
				if !yield(v) {
					return
				}
			}
		}
	}
}

func main() {
	numbers := slicesToIter([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})

	evens := Filter(numbers, func(n int) bool { return n%2 == 0 })
	squares := Map(evens, func(n int) int { return n * n })
	first3 := Take(3, squares)

	fmt.Print("鏈式操作: ")
	for v := range first3 {
		fmt.Print(v, " ") // 4 16 36
	}
	fmt.Println()

	sum := Reduce(slicesToIter([]int{1, 2, 3, 4, 5}), 0,
		func(acc, n int) int { return acc + n })
	fmt.Println("求和:", sum) // 15

	fmt.Print("分塊: ")
	for chunk := range Chunk(3, slicesToIter([]int{1, 2, 3, 4, 5, 6, 7})) {
		fmt.Print(chunk, " ")
	}
	fmt.Println()

	fmt.Print("去重: ")
	for v := range Distinct(slicesToIter([]string{"go", "rust", "go", "python", "rust"})) {
		fmt.Print(v, " ")
	}
	fmt.Println()
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s {
			if !yield(v) {
				return
			}
		}
	}
}

模式三:樹/圖遍歷迭代器

迭代器最強大的應用場景——將遞迴遍歷變成可組合的管道。

// go-tree-iterator/main.go
// 執行環境: Go 1.24+ / 無額外依賴
package main

import (
	"fmt"
	"iter"
)

type TreeNode[T any] struct {
	Value T
	Left  *TreeNode[T]
	Right *TreeNode[T]
}

// InOrder 中序遍歷迭代器(左-根-右)
func (n *TreeNode[T]) InOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		n.inOrderHelper(yield)
	}
}

func (n *TreeNode[T]) inOrderHelper(yield func(T) bool) bool {
	if n == nil {
		return true
	}
	if !n.Left.inOrderHelper(yield) {
		return false
	}
	if !yield(n.Value) {
		return false
	}
	if !n.Right.inOrderHelper(yield) {
		return false
	}
	return true
}

// PreOrder 前序遍歷迭代器(根-左-右)
func (n *TreeNode[T]) PreOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		n.preOrderHelper(yield)
	}
}

func (n *TreeNode[T]) preOrderHelper(yield func(T) bool) bool {
	if n == nil {
		return true
	}
	if !yield(n.Value) {
		return false
	}
	if !n.Left.preOrderHelper(yield) {
		return false
	}
	if !n.Right.preOrderHelper(yield) {
		return false
	}
	return true
}

// LevelOrder 層序遍歷迭代器(BFS)
func (n *TreeNode[T]) LevelOrder() iter.Seq[T] {
	return func(yield func(T) bool) {
		if n == nil {
			return
		}
		queue := []*TreeNode[T]{n}
		for len(queue) > 0 {
			current := queue[0]
			queue = queue[1:]
			if !yield(current.Value) {
				return
			}
			if current.Left != nil {
				queue = append(queue, current.Left)
			}
			if current.Right != nil {
				queue = append(queue, current.Right)
			}
		}
	}
}

// Graph 圖定義
type Graph[T comparable] struct {
	adjList map[T][]T
}

func NewGraph[T comparable]() *Graph[T] {
	return &Graph[T]{adjList: make(map[T][]T)}
}

func (g *Graph[T]) AddEdge(from, to T) {
	g.adjList[from] = append(g.adjList[from], to)
}

// DFS 深度優先遍歷迭代器
func (g *Graph[T]) DFS(start T) iter.Seq[T] {
	return func(yield func(T) bool) {
		visited := make(map[T]bool)
		g.dfsHelper(start, visited, yield)
	}
}

func (g *Graph[T]) dfsHelper(node T, visited map[T]bool, yield func(T) bool) bool {
	if visited[node] {
		return true
	}
	visited[node] = true
	if !yield(node) {
		return false
	}
	for _, neighbor := range g.adjList[node] {
		if !g.dfsHelper(neighbor, visited, yield) {
			return false
		}
	}
	return true
}

// BFS 廣度優先遍歷迭代器
func (g *Graph[T]) BFS(start T) iter.Seq[T] {
	return func(yield func(T) bool) {
		visited := make(map[T]bool)
		queue := []T{start}
		visited[start] = true
		for len(queue) > 0 {
			node := queue[0]
			queue = queue[1:]
			if !yield(node) {
				return
			}
			for _, neighbor := range g.adjList[node] {
				if !visited[neighbor] {
					visited[neighbor] = true
					queue = append(queue, neighbor)
				}
			}
		}
	}
}

func main() {
	root := &TreeNode[int]{
		Value: 4,
		Left:  &TreeNode[int]{Value: 2, Left: &TreeNode[int]{Value: 1}, Right: &TreeNode[int]{Value: 3}},
		Right: &TreeNode[int]{Value: 6, Left: &TreeNode[int]{Value: 5}, Right: &TreeNode[int]{Value: 7}},
	}

	fmt.Print("中序: ")
	for v := range root.InOrder() { fmt.Print(v, " ") }
	fmt.Println()

	fmt.Print("前序: ")
	for v := range root.PreOrder() { fmt.Print(v, " ") }
	fmt.Println()

	fmt.Print("層序: ")
	for v := range root.LevelOrder() { fmt.Print(v, " ") }
	fmt.Println()

	g := NewGraph[string]()
	g.AddEdge("A", "B")
	g.AddEdge("A", "C")
	g.AddEdge("B", "D")
	g.AddEdge("C", "D")
	g.AddEdge("D", "E")

	fmt.Print("DFS: ")
	for v := range g.DFS("A") { fmt.Print(v, " ") }
	fmt.Println()

	fmt.Print("BFS: ")
	for v := range g.BFS("A") { fmt.Print(v, " ") }
	fmt.Println()
}

模式四:迭代器組合與管道

迭代器最優雅的用法——像Unix管道一樣組合資料處理流程。

// go-iterator-pipeline/main.go
// 執行環境: Go 1.24+ / 無額外依賴
package main

import (
	"fmt"
	"iter"
	"strings"
)

// Concat 連線多個迭代器
func Concat[T any](seqs ...iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, seq := range seqs {
			for v := range seq {
				if !yield(v) { return }
			}
		}
	}
}

// Interleave 交替輸出多個迭代器的元素
func Interleave[T any](seqs ...iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		pulls := make([]func() (T, bool), len(seqs))
		stops := make([]func(), len(seqs))
		for i, seq := range seqs {
			pulls[i], stops[i] = iter.Pull(seq)
		}
		defer func() { for _, stop := range stops { stop() } }()

		active := len(seqs)
		for active > 0 {
			for i, pull := range pulls {
				v, ok := pull()
				if !ok { pulls[i] = nil; active--; continue }
				if !yield(v) { return }
			}
		}
	}
}

// TakeWhile 在條件為true時取值
func TakeWhile[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if !predicate(v) { return }
			if !yield(v) { return }
		}
	}
}

// DropWhile 跳過條件為true的元素
func DropWhile[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		dropping := true
		for v := range seq {
			if dropping && predicate(v) { continue }
			dropping = false
			if !yield(v) { return }
		}
	}
}

// 日誌處理管道
type LogEntry struct {
	Timestamp string
	Level     string
	Message   string
}

func ParseLogs(rawLines iter.Seq[string]) iter.Seq[LogEntry] {
	return Map(rawLines, func(line string) LogEntry {
		parts := strings.SplitN(line, " ", 3)
		if len(parts) < 3 { return LogEntry{Message: line} }
		return LogEntry{Timestamp: parts[0], Level: parts[1], Message: parts[2]}
	})
}

func FilterByLevel(level string, logs iter.Seq[LogEntry]) iter.Seq[LogEntry] {
	return Filter(logs, func(l LogEntry) bool { return l.Level == level })
}

func ExtractMessages(logs iter.Seq[LogEntry]) iter.Seq[string] {
	return Map(logs, func(l LogEntry) string { return l.Message })
}

func main() {
	fmt.Print("連線: ")
	for v := range Concat(slicesToIter([]int{1, 2, 3}), slicesToIter([]int{4, 5, 6})) {
		fmt.Print(v, " ")
	}
	fmt.Println()

	fmt.Print("交替: ")
	for v := range Interleave(slicesToIter([]string{"A", "B", "C"}), slicesToIter([]string{"1", "2", "3"})) {
		fmt.Print(v, " ")
	}
	fmt.Println()

	rawLogs := slicesToIter([]string{
		"2026-01-01 ERROR 資料庫連線失敗",
		"2026-01-01 INFO 服務啟動",
		"2026-01-01 ERROR 快取超時",
		"2026-01-01 WARN 記憶體使用率高",
	})

	fmt.Println("\n=== 日誌管道:只看ERROR訊息 ===")
	for msg := range ExtractMessages(FilterByLevel("ERROR", ParseLogs(rawLogs))) {
		fmt.Println("  ", msg)
	}
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s { if !yield(v) { return } }
	}
}

func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T] {
	return func(yield func(T) bool) {
		for v := range seq {
			if predicate(v) { if !yield(v) { return } }
		}
	}
}

func Map[T any, R any](seq iter.Seq[T], transform func(T) R) iter.Seq[R] {
	return func(yield func(R) bool) {
		for v := range seq { if !yield(transform(v)) { return } }
	}
}

func Take[T any](n int, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		count := 0
		for v := range seq {
			if count >= n { return }
			if !yield(v) { return }
			count++
		}
	}
}

模式五:生產級迭代器模式

將迭代器應用於真實的生產場景:資料庫分頁、檔案串流處理、併發迭代。

// go-production-iterator/main.go
// 執行環境: Go 1.24+ / 無額外依賴
package main

import (
	"bufio"
	"fmt"
	"iter"
	"strings"
)

// 分頁迭代器
type Page[T any] struct {
	Items   []T
	PageNum int
	HasMore bool
}

func Paginate[T any](fetchPage func(pageNum int) (Page[T], error)) iter.Seq2[int, T] {
	return func(yield func(int, T) bool) {
		pageNum := 0
		for {
			page, err := fetchPage(pageNum)
			if err != nil { return }
			for _, item := range page.Items {
				if !yield(pageNum, item) { return }
			}
			if !page.HasMore { return }
			pageNum++
		}
	}
}

// 檔案行迭代器
func LinesFromString(s string) iter.Seq[string] {
	return func(yield func(string) bool) {
		scanner := bufio.NewScanner(strings.NewReader(s))
		for scanner.Scan() {
			if !yield(scanner.Text()) { return }
		}
	}
}

// 滑動視窗迭代器
func SlidingWindow[T any](size int, seq iter.Seq[T]) iter.Seq[[]T] {
	return func(yield func([]T) bool) {
		window := make([]T, 0, size)
		for v := range seq {
			window = append(window, v)
			if len(window) > size { window = window[1:] }
			if len(window) == size {
				snapshot := make([]T, size)
				copy(snapshot, window)
				if !yield(snapshot) { return }
			}
		}
	}
}

// 有序去重
func Deduplicate[T comparable](seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		var prev T
		first := true
		for v := range seq {
			if first || v != prev {
				first = false
				prev = v
				if !yield(v) { return }
			}
		}
	}
}

func main() {
	// 分頁迭代器
	fmt.Println("=== 分頁迭代器 ===")
	mockFetchPage := func(pageNum int) (Page[string], error) {
		allItems := [][]string{{"使用者1", "使用者2", "使用者3"}, {"使用者4", "使用者5"}, {"使用者6"}}
		if pageNum >= len(allItems) { return Page[string]{HasMore: false}, nil }
		return Page[string]{Items: allItems[pageNum], PageNum: pageNum, HasMore: pageNum < len(allItems)-1}, nil
	}
	for pageNum, user := range Paginate(mockFetchPage) {
		fmt.Printf("  頁%d: %s\n", pageNum, user)
	}

	// 滑動視窗
	fmt.Println("\n=== 滑動視窗 ===")
	for window := range SlidingWindow(3, slicesToIter([]int{1, 2, 3, 4, 5, 6, 7})) {
		fmt.Print(window, " ")
	}
	fmt.Println()

	// 有序去重
	fmt.Print("有序去重: ")
	for v := range Deduplicate(slicesToIter([]int{1, 1, 2, 2, 3, 3, 3, 4})) {
		fmt.Print(v, " ")
	}
	fmt.Println()
}

func slicesToIter[T any](s []T) iter.Seq[T] {
	return func(yield func(T) bool) {
		for _, v := range s { if !yield(v) { return } }
	}
}

避坑指南:5個常見陷阱

坑1:迭代器中修改底層集合

// ❌ 錯誤:遍歷時修改切片導致未定義行為
for i, v := range mySlice {
    mySlice = append(mySlice, v) // 危險!
}

// ✅ 正確:先複製再遍歷
copied := make([]int, len(mySlice))
copy(copied, mySlice)
for v := range slicesToIter(copied) { /* 安全 */ }

坑2:Pull迭代器忘記呼叫stop

// ❌ 錯誤:Pull後未呼叫stop
next, _ := iter.Pull(mySeq)  // stop被忽略了!

// ✅ 正確:始終defer stop
next, stop := iter.Pull(mySeq)
defer stop()

坑3:迭代器重用導致意外行為

// ❌ 錯誤:迭代器是消耗性的
seq := Range(5)
for v := range seq { fmt.Print(v) } // 0 1 2 3 4
for v := range seq { fmt.Print(v) } // 無輸出!

// ✅ 正確:每次建立新迭代器
for v := range Range(5) { fmt.Print(v) }
for v := range Range(5) { fmt.Print(v) }

坑4:遞迴迭代器棧溢位

深度遞迴樹可能導致棧溢位,改用顯式棧(層序遍歷方式)實現。

坑5:goroutine洩漏

Buffered迭代器中消費者提前退出時,確保done channel能通知生產者退出。

報錯排查表

報錯資訊 原因 解決方案
cannot range over xxx 型別不是iter.Seq/iter.Seq2 確認函式簽名
yield is not used 迭代器函式中未呼叫yield 確保呼叫yield(v)
cannot use seq as iter.Seq 迭代器簽名不匹配 檢查iter.Seq[T]vsiter.Seq2[K,V]
panic: range over nil 迭代器函式為nil 新增nil檢查
goroutine leak Pull迭代器未呼叫stop defer stop()
stack overflow 遞迴迭代器深度過大 改用顯式棧迭代
deadlock 迭代器內部channel阻塞 新增context取消或超時機制
unexpected address yield回傳的是副本 Go值語義,需要取地址請用指標*T
iterator consumed twice 迭代器只能消耗一次 每次建立新迭代器
invalid memory address 迭代器中存取已關閉資源 確保資源在迭代完成後才關閉

進階最佳化:5個生產級技巧

技巧1:迭代器與context整合

func ContextAware[T any](ctx context.Context, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		next, stop := iter.Pull(seq)
		defer stop()
		for {
			select {
			case <-ctx.Done():
				return
			default:
				v, ok := next()
				if !ok { return }
				if !yield(v) { return }
			}
		}
	}
}

技巧2:並行迭代器

使用goroutine和channel實現ParallelMap,並行處理迭代器元素。

技巧3:迭代器效能基準

使用Go benchmark對比迭代器與傳統for迴圈的效能差異。

技巧4:自訂集合實作iter介面

為OrderedMap等自訂集合實作All()Keys()Values()迭代器方法。

技巧5:迭代器中介軟體模式

func WithMetrics[T any](name string, seq iter.Seq[T]) iter.Seq[T] {
	return func(yield func(T) bool) {
		count := 0
		start := time.Now()
		for v := range seq {
			count++
			if !yield(v) {
				log.Printf("[ITER:%s] interrupted after %d items", name, count)
				return
			}
		}
		log.Printf("[ITER:%s] completed %d items, elapsed: %v", name, count, time.Since(start))
	}
}

Go迭代器 vs 其他語言對比

維度 Go 1.24 iter Python Generator Rust Iterator Java Stream
型別 func(yield func(V) bool) yield v trait Iterator Stream<T>
泛型 ✅ 完整泛型 ❌ 動態型別 ✅ 完整泛型 ✅ 完整泛型
懶求值 ✅ 天然懶 ✅ 天然懶 ✅ 天然懶 ✅ 可选拉/推
提前退出 ✅ yield回傳false ✅ break ✅ take/scan ⚠️ 需短路操作
組合性 ✅ 函式組合 ✅ 生成器組合 ✅ adapter組合 ✅ 串流操作
併發安全 ❌ 非併發安全 ❌ GIL限制 ❌ 非併發安全 ✅ 平行串流
效能開銷 低(函式呼叫) 高(解釋執行) 零成本抽象 中(裝箱/拆箱)
學習曲線 中高
生態成熟度 新(1.23引入) 成熟 成熟 成熟

總結

Go 1.24的range over func迭代器是Go語言表達力的重要提升:

  • 基礎模式:理解iter.Seq[T]iter.Seq2[K,V]兩種簽名,掌握yield回傳false的提前退出機制
  • 泛型迭代器:Filter/Map/Reduce/Chunk等工具函式讓資料處理像管道一樣優雅
  • 樹/圖遍歷:將遞迴遍歷封裝為迭代器,可組合、可中斷、可複用
  • 迭代器管道:Concat/Interleave/TakeWhile/DropWhile實現資料流組合
  • 生產級模式:分頁迭代器、檔案串流、滑動視窗、帶context取消

關鍵原則:迭代器是消耗性的、非併發安全的、天然懶求值的。理解這三點,就能避免90%的坑。

線上工具推薦

本站提供瀏覽器本地工具,免註冊即可試用 →

#Go 1.24#迭代器#range over func#泛型迭代器#Go新特性#2026#编程语言