Ramai orang nampaknya keliru dengan iterator yang baru ditambah dalam Go, itulah sebabnya saya memutuskan untuk menulis satu lagi artikel cuba menerangkannya dengan cara yang semudah mungkin.
Pertama, saya fikir adalah penting untuk memahami cara iterator dipanggil dan digunakan oleh Go, dan ia sebenarnya agak mudah, mari kita gunakan kepingan.Semua iterator sebagai contoh. Berikut ialah cara anda biasanya menggunakan iterator ini:
package main import ( "fmt" "slices" ) func main() { slice := []string{ "Element 1", "Element 2", "Element 3", "Element 4", } for index, element := range slices.All(slice) { if index >= 2 { break } fmt.Println(index, element) } // Output: // 0 Element 1 // 1 Element 2 }
Dan inilah rupa sebenarnya:
package main import ( "fmt" "slices" ) func main() { slice := []string{ "Element 1", "Element 2", "Element 3", "Element 4", } slices.All(slice)(func (index int, element string) bool { if index >= 2 { return false // break } fmt.Println(index, element) return true // continue loop as normal }) // Output: // 0 Element 1 // 1 Element 2 }
Apa yang berlaku ialah badan gelung sedang "digerakkan" untuk menghasilkan fungsi yang dihantar kepada lelaran, manakala continue dan break masing-masing diubah untuk mengembalikan true dan return false. return true juga ditambahkan pada penghujung gelung untuk menandakan bahawa kami ingin mendapatkan elemen seterusnya, jika tiada keputusan lain yang dibuat sebelum ini.
Ini bukan pendedahan yang tepat tentang apa yang dilakukan pengkompil dan saya belum menyemak pelaksanaan Go untuk menyemak ini, tetapi mereka menghasilkan hasil yang setara daripada pemerhatian saya.
Sekarang, setelah anda memahami cara mereka dipanggil dan menyedari betapa mudahnya ia sebenarnya, lebih mudah untuk memahami cara mencipta iterator anda sendiri dan pelaksanaannya.
Mari kita buat iterator nyahpepijat yang akan mencetak mesej nyahpepijat untuk setiap langkah pelaksanaan iterator yang akan meninjau semua elemen dalam kepingan (slices.Semua fungsi).
Pertama, saya akan mencipta fungsi pembantu kecil untuk log keluar mesej dengan masa pelaksanaan semasa.
import ( "fmt" "time" ) var START time.Time = time.Now() func logt(message string) { fmt.Println(time.Since(START), message) }
Kembali kepada iterator:
import ( "iter" ) func DebugIter[E any](slice []E) iter.Seq2[int, E] { logt("DebugIter called") // the same way iter.All returned function // we called in order to iterate over slice // here we are returning a function to // iterate over all slice elements too return func(yield func(int, E) bool) { logt("Seq2 return function called, starting loop") for index, element := range slice { logt("in loop, calling yield") shouldContinue := yield(index, element) if !shouldContinue { logt("in loop, yield returned false") return } logt("in loop, yield returned true") } } }
Saya telah menambah beberapa kenyataan cetakan nyahpepijat supaya kita dapat melihat dengan lebih baik susunan pelaksanaan iterator dan cara ia bertindak balas terhadap kata kunci yang berbeza seperti putus dan teruskan.
Akhir sekali, mari gunakan iterator yang dilaksanakan:
func main() { slice := []string{ "Element 1", "Element 2", "Element 3", "Element 4", } for index, element := range DebugIter(slice) { message := "got element in range of iter: " + element logt(message) if index >= 2 { break } if index > 0 { continue } time.Sleep(2 * time.Second) logt("ended sleep in range of iter") } }
Akan memberikan kami output:
11.125µs DebugIter called 39.292µs Seq2 return function called, starting loop 42.459µs in loop, calling yield 44.292µs got element in range of iter: Element 1 2.001194292s ended sleep in range of iter 2.001280459s in loop, yield returned true 2.001283917s in loop, calling yield 2.001287042s got element in range of iter: Element 2 2.001291084s in loop, yield returned true 2.001293125s in loop, calling yield 2.0012955s got element in range of iter: Element 3 2.001297542s in loop, yield returned false
Contoh ini menunjukkan dengan baik cara iterator berfungsi dan dilaksanakan. Apabila menggunakan iterator dalam gelung julat semua arahan dalam blok gelung adalah jenis "dipindahkan" ke fungsi yang dipanggil hasil. Apabila kita memanggil hasil, kita pada asasnya meminta go runtime untuk melaksanakan apa sahaja yang terdapat dalam blok gelung dengan nilai berikut untuk lelaran ini, itulah juga sebabnya hasil akan disekat, jika badan gelung akan disekat. Sekiranya masa jalanan menentukan bahawa lelaran gelung ini sepatutnya berhenti, hasil akan kembali palsu, ia boleh berlaku apabila kata kunci pemecahan dipenuhi semasa pelaksanaan blok gelung, kita tidak seharusnya memanggil hasil lagi jika itu berlaku. Jika tidak, kita harus terus memanggil hasil.
Kod penuh:
package main import ( "fmt" "time" "iter" ) var START time.Time = time.Now() func logt(message string) { fmt.Println(time.Since(START), message) } func DebugIter[E any](slice []E) iter.Seq2[int, E] { logt("DebugIter called") // the same way iter.All returned function // we called in order to iterate over slice // here we are returning a function to // iterate over all slice elements too return func(yield func(int, E) bool) { logt("Seq2 return function called, starting loop") for index, element := range slice { logt("in loop, calling yield for") shouldContinue := yield(index, element) if !shouldContinue { logt("in loop, yield returned false") return } logt("in loop, yield returned true") } } } func main() { slice := []string{ "Element 1", "Element 2", "Element 3", "Element 4", } for index, element := range DebugIter(slice) { message := "got element in range of iter: " + element logt(message) if index >= 2 { break } if index > 0 { continue } time.Sleep(2 * time.Second) logt("ended sleep in range of iter") } // unfold compiler magic // DebugIter(slice)(func (index int, element string) bool { // message := "got element in range of iter: " + element // logt(message) // if index >= 2 { // return false // } // if index > 0 { // return true // } // time.Sleep(2 * time.Second) // logt("ended sleep in range of iter") // // return true // }) }
Atas ialah kandungan terperinci Memahami terator Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!