"यदि कोई कर्मचारी अपना काम अच्छी तरह से करना चाहता है, तो उसे पहले अपने औजारों को तेज करना होगा।" - कन्फ्यूशियस, "द एनालेक्ट्स ऑफ कन्फ्यूशियस। लू लिंगगोंग"
मुखपृष्ठ > प्रोग्रामिंग > गो टेरेटर्स को समझना

गो टेरेटर्स को समझना

2024-08-21 को प्रकाशित
ब्राउज़ करें:525

Understanding Go terators

बहुत से लोग गो में नए जोड़े गए इटरेटर्स से भ्रमित हो जाते हैं, इसीलिए मैंने उन्हें यथासंभव सरल तरीके से समझाने का प्रयास करते हुए एक और लेख लिखने का फैसला किया।

उन्हें गो नाम से कैसे बुलाया जाता है?

सबसे पहले, मुझे लगता है कि यह समझना महत्वपूर्ण है कि गो द्वारा इटरेटर्स को कैसे बुलाया और उपयोग किया जा रहा है, और यह वास्तव में बहुत सरल है, आइए एक उदाहरण के रूप में स्लाइस.ऑल इटरेटर का उपयोग करें। यहां बताया गया है कि आप सामान्यतः इस पुनरावर्तक का उपयोग कैसे करेंगे:

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
}

और यह वास्तव में कैसा दिखता है:

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
}

क्या होता है कि लूप बॉडी को यील्ड फ़ंक्शन के लिए "स्थानांतरित" किया जाता है जिसे इटरेटर को पास कर दिया जाता है, जबकि जारी रखें और ब्रेक को क्रमशः सही और रिटर्न गलत में परिवर्तित किया जा रहा है। यह संकेत देने के लिए कि हम अगला तत्व प्राप्त करना चाहते हैं, लूप के अंत में return true भी जोड़ा जाता है, यदि पहले कोई और निर्णय नहीं लिया गया हो।

यह कंपाइलर जो कर रहा है उसका सटीक खुलासा नहीं है और मैंने इसे जांचने के लिए गो कार्यान्वयन की जांच नहीं की है, लेकिन वे मेरी टिप्पणियों से समकक्ष परिणाम उत्पन्न करते हैं।

अपना खुद का इटरेटर कैसे बनाएं और उसका निष्पादन कैसे करें

अब, जब आप समझ गए हैं कि उन्हें कैसे बुलाया जा रहा है और यह महसूस किया है कि यह वास्तव में कितना सरल है, तो यह समझना बहुत आसान हो जाएगा कि अपना खुद का इटरेटर कैसे बनाएं और उसका निष्पादन कैसे करें।

आइए एक डिबग इटरेटर बनाएं जो इटरेटर कार्यान्वयन के प्रत्येक चरण के लिए डिबग संदेशों को प्रिंट करेगा जो स्लाइस (स्लाइस.सभी कार्यक्षमता) में सभी तत्वों पर चलेगा।

सबसे पहले, मैं वर्तमान निष्पादन समय के साथ संदेश को लॉग आउट करने के लिए छोटा सहायक फ़ंक्शन बनाऊंगा।

import (
    "fmt"
    "time"
)

var START time.Time = time.Now()

func logt(message string) {
    fmt.Println(time.Since(START), message)
}

इटरेटर पर वापस जाएं:

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")
        }
    }
}

मैंने कुछ डिबग प्रिंट स्टेटमेंट जोड़े हैं ताकि हम इटरेटर के निष्पादन के क्रम को बेहतर ढंग से देख सकें और यह ब्रेक और जारी रखने जैसे विभिन्न कीवर्ड पर कैसे प्रतिक्रिया करेगा।

अंत में, आइए कार्यान्वित इटरेटर का उपयोग करें:

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")
    }
}

हमें आउटपुट देगा:

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

यह उदाहरण बहुत अच्छी तरह से दिखाता है कि इटरेटर कैसे काम करता है और निष्पादित होता है। रेंज लूप में इटरेटर का उपयोग करते समय लूप ब्लॉक के सभी निर्देश एक फ़ंक्शन में "स्थानांतरित" हो जाते हैं जिसे यील्ड कहा जाता है। जब हम यील्ड कहते हैं तो हम अनिवार्य रूप से इस पुनरावृत्ति के लिए निम्नलिखित मान के साथ लूप ब्लॉक में स्थित किसी भी चीज़ को निष्पादित करने के लिए रनटाइम पर जाने के लिए कहते हैं, यही कारण है कि यदि लूप बॉडी अवरुद्ध हो जाएगी तो यील्ड अवरुद्ध हो जाएगी। यदि रनटाइम यह निर्धारित करता है कि इस लूप पुनरावृत्ति को रोकना चाहिए, तो यील्ड गलत हो जाएगी, यह तब हो सकता है जब लूप ब्लॉक निष्पादन के दौरान ब्रेक कीवर्ड पूरा हो जाता है, यदि ऐसा होता है तो हमें यील्ड को कॉल नहीं करना चाहिए। अन्यथा, हमें यील्ड कॉल करना जारी रखना चाहिए।

पूर्ण कोड:

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
    //  })
}
विज्ञप्ति वक्तव्य यह आलेख यहां पुन: प्रस्तुत किया गया है: https://dev.to/wmdanor/understanding-go-123-iterators-3ai1?1 यदि कोई उल्लंघन है, तो कृपया इसे हटाने के लिए [email protected] से संपर्क करें।
नवीनतम ट्यूटोरियल अधिक>

चीनी भाषा का अध्ययन करें

अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।

Copyright© 2022 湘ICP备2022001581号-3