河源網(wǎng)站建設(shè)武漢百度推廣公司
🌈Don’t worry , just coding!
內(nèi)耗與overthinking只會削弱你的精力,虛度你的光陰,每天邁出一小步,回頭時發(fā)現(xiàn)已經(jīng)走了很遠(yuǎn)。
📗概念
在 Go 語言中,迭代器的實現(xiàn)通常不是通過語言內(nèi)置的迭代器類型,而是通過自定義類型和方法來實現(xiàn)的。下面是一個簡單的示例,展示如何在 Go 中實現(xiàn)一個迭代器。
💻代碼
迭代器
package mainimport "fmt"// IntSliceIterator 是一個自定義的迭代器,用于迭代整數(shù)切片
type IntSliceIterator struct {//data:存儲要迭代的整數(shù)切片。//index:當(dāng)前迭代的位置。data []intindex int
}// 定義NewIntSliceIterator函數(shù),輸入data切片類型為int
// 返回一個指向 IntSliceIterator 結(jié)構(gòu)體的指針。
func NewIntSliceIterator(data []int) *IntSliceIterator {//&IntSliceIterator{} 創(chuàng)建了一個新的 IntSliceIterator 實例并返回return &IntSliceIterator{data: data,index: 0,}
}// HasNext 檢查是否還有下一個元素
func (it *IntSliceIterator) HasNext() bool {return it.index < len(it.data)
}// 定義Next函數(shù) 返回下一個元素并移動迭代器
// 輸入*IntSliceIterator指針,賦值給it變量
// 返回一個int類型
func (it *IntSliceIterator) Next() int {if !it.HasNext() {//如果沒有更多元素,使用 panic 拋出一個錯誤panic("No more elements")}//從data 切片中獲取當(dāng)前索引 it.index 指向的元素,并將其賦值給 value。value := it.data[it.index]//將 index 增加 1,下次調(diào)用時指向下一個元素。it.index++return value
}func main() {data := []int{1, 2, 3, 4, 5}iterator := NewIntSliceIterator(data)for iterator.HasNext() {fmt.Println(iterator.Next())}
}//輸出
//1
//2
//3
//4
//5
yeild
在python中yeild表示本次執(zhí)行結(jié)束并返回值,類似于return,yeild和return不同的地方在于yeild可以優(yōu)雅的返回每次調(diào)用時的值。
在go中沒有yeild關(guān)鍵字,我們用yeild方便理解。
package mainimport ("fmt""iter""slices"
)// 這不是來了么,定義一個泛型List 任意類型的struct
type List[T any] struct {head, tail *element[T]
}// 老樣子,定義element泛型struct 任意類型,是一個鏈表
type element[T any] struct {next *element[T]val T
}// 鏈表的push方法
func (lst *List[T]) Push(v T) {if lst.tail == nil {lst.head = &element[T]{val: v}lst.tail = lst.head} else {lst.tail.next = &element[T]{val: v}lst.tail = lst.tail.next}
}// 輸入為lst,類型為 *List[T],返回一個函數(shù),這個函數(shù)的類型是 iter.Seq[T],是一個迭代器
func (lst *List[T]) All() iter.Seq[T] {//返回值是一個匿名函數(shù),接受一個參數(shù) yield,這個參數(shù)是一個函數(shù)類型,接受一個類型為 T 的參數(shù)并返回一個布爾值return func(yield func(T) bool) {//初始化 e 為鏈表的頭節(jié)點//循環(huán)條件為 e != nil//e = e.next 將e指向鏈表下一個節(jié)點for e := lst.head; e != nil; e = e.next {//調(diào)用yield,如果yield 返回 false,則退出循環(huán),結(jié)束遍歷if !yield(e.val) {return}}}
}// 斐波那契數(shù)列生成
// 定義函數(shù)genFib
// 輸入?yún)?shù)沒有
// 返回一個函數(shù) int類型
func genFib() iter.Seq[int] {//返回一個匿名函數(shù)func,該匿名函數(shù)接受一個參數(shù) yield,這個參數(shù)是一個函數(shù)類型,接受一個 int 類型的參數(shù)并返回一個布爾值。return func(yield func(int) bool) {//賦值a, b := 1, 1//調(diào)用yield,如果yield 返回 false,則退出循環(huán)for {if !yield(a) {return}a, b = b, a+b}}
}func main() {lst := List[int]{}lst.Push(10)lst.Push(13)lst.Push(23)for e := range lst.All() {fmt.Println(e)}//lst 是一個鏈表,調(diào)用 All() 方法會返回一個迭代器//這個生成器會遍歷鏈表中的所有元素,并通過 yield 函數(shù)逐個返回這些元素。all := slices.Collect(lst.All()) //slices.Collect(...) 函數(shù)遍歷生成器,收集所有元素fmt.Println("all:", all)//調(diào)用genFib,賦值給nfor n := range genFib() {//當(dāng)n>=10跳出循環(huán)if n >= 10 {break}fmt.Println(n)}
}//輸出
//10
//13
//23
//all: [10 13 23]
//1
//1
//2
//3
//5
//8
💡 Tips小知識點
迭代器和生成器
在 Go 語言中,生成器和迭代器是處理序列數(shù)據(jù)的兩種不同概念,雖然它們有相似之處,但在實現(xiàn)和使用上有一些關(guān)鍵的區(qū)別。
- 生成器是一種函數(shù),它可以逐步生成一系列值,而不是一次性返回所有值。生成器通常使用 yield 關(guān)鍵字(在 Go 中通常通過返回一個函數(shù)來模擬)來返回下一個值,并保持其狀態(tài),以便在下一次調(diào)用時繼續(xù)執(zhí)行。
- 生成器通常在需要時生成值,適用于需要惰性求值的場景。調(diào)用生成器時,可以獲取下一個值,而不需要事先知道所有值。
- 生成器通過閉包保持狀態(tài),允許在多次調(diào)用之間保留局部變量的值。
- 迭代器是一種對象,它實現(xiàn)了特定的接口(通常包含 Next() 方法),用于遍歷集合中的元素。迭代器維護(hù)一個內(nèi)部狀態(tài),允許用戶逐步訪問集合的每個元素。
- 迭代器通常用于遍歷整個集合,通過調(diào)用 Next() 方法來獲取下一個元素,直到?jīng)]有更多元素可供訪問。
- 迭代器通過結(jié)構(gòu)體的字段來管理狀態(tài),通常在結(jié)構(gòu)體中維護(hù)當(dāng)前元素的指針或索引。
生成器Example
func genFib() func() int {a, b := 0, 1return func() int {a, b = b, a+breturn a}
}
迭代器Example
type Iterator struct {current *Node
}func (it *Iterator) Next() *Node {if it.current == nil {return nil}node := it.currentit.current = it.current.nextreturn node
}
💪無人扶我青云志,我自踏雪至山巔。