Kotlin के forEach में break और continue क्यों काम नहीं करते (और इसे कैसे ठीक करें)
\n\nअगर आपने कभी Kotlin में कोड लिखा है और forEach लूप से जल्दी बाहर निकलने के लिए break का उपयोग करने की कोशिश की है, तो शायद आपको IDE में लाल रेखा और कंपाइलेशन एरर मिली होगी। परिचित लग रहा है? आप अकेले नहीं हैं — यह Stack Overflow पर Kotlin से जुड़े सबसे लोकप्रिय सवालों में से एक है, जिसे हजारों बार देखा गया है। इस लेख में हम सिर्फ यह नहीं दिखाएंगे कि इस सीमा को कैसे पार किया जाए, बल्कि अंदरूनी तंत्र को भी समझेंगे: ऐसा क्यों बनाया गया, लैम्ब्डा के अंदर return कैसे काम करता है, और कौन से विकल्प मौजूद हैं। चलिए शुरू करते हैं!
शुरुआती गलती का क्लासिक उदाहरण
\n\nमान लीजिए आपके पास संख्याओं की एक सूची है, और आपको स्क्रीन पर केवल पहले तीन तत्वों को प्रिंट करना है। सहज रूप से आप ऐसा लिखना चाहेंगे:
\n\nval numbers = listOf(1, 2, 3, 4, 5)\nnumbers.forEach {\n println(it)\n if (it == 3) break // कंपाइलेशन एरर!\n}\n\n\nकंपाइलर एक एरर देगा: ‘break’ और ‘continue’ केवल लूप के अंदर ही अनुमत हैं। ऐसा क्यों? आखिर forEach तो एक लूप जैसा लगता है? इसका जवाब इस बात में छिपा है कि forEach वास्तव में कैसे काम करता है।
forEach की शारीरिक रचना: यह लूप नहीं, बल्कि एक फंक्शन कॉल है
\n\nआइए Kotlin की स्टैंडर्ड लाइब्रेरी खोलें और forEach के सिग्नेचर को देखें:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {\n for (element in this) action(element)\n}\n\n\nयहाँ मुख्य शब्द है inline। इसका मतलब है कि कंपाइलेशन के समय, फंक्शन का बॉडी सीधे कॉल वाली जगह पर डाल दिया जाता है। लेकिन फिर भी, forEach एक हायर-ऑर्डर फंक्शन है जो दूसरे फंक्शन (लैम्ब्डा) को आर्गुमेंट के रूप में लेता है। और लैम्ब्डा कोड का कोई लूप ब्लॉक नहीं है, बल्कि एक सामान्य फंक्शन-ऑब्जेक्ट है। break और continue का अर्थ केवल for, while या do-while कंस्ट्रक्शन के अंदर होता है, किसी भी फंक्शन के अंदर नहीं।
दूसरे शब्दों में, जब आप numbers.forEach { ... } लिखते हैं, तो आप एक लूप नहीं बना रहे हैं — आप एक मेथड को कॉल कर रहे हैं जो अपने अंदर for लूप का उपयोग करता है। कंपाइलर आपके लैम्ब्डा से break को बाहरी लूप में नहीं भेज सकता, क्योंकि लैम्ब्डा एक अलग इकाई है। यह कोई बग नहीं, बल्कि एक डिज़ाइन है।
forEach में return कैसे काम करता है (अप्रत्याशित मोड़)
\n\nलेकिन forEach के अंदर return काम करता है... लेकिन उस तरह नहीं जैसा आप उम्मीद करते हैं। देखिए:
fun main() {\n val numbers = listOf(1, 2, 3, 4, 5)\n numbers.forEach {\n if (it == 3) return // main() से बाहर निकल जाएगा!\n println(it)\n }\n println("यह लाइन नहीं चलेगी")\n}\n\n\nआउटपुट होगा: 1 2। यहाँ return एक non-local return (गैर-स्थानीय वापसी) है। यह सिर्फ लैम्ब्डा को नहीं, बल्कि पूरे बाहरी फंक्शन (main) को समाप्त कर देता है। यह इसलिए काम करता है क्योंकि forEach को inline घोषित किया गया है। कंपाइलर लैम्ब्डा के कोड को सीधे main के बॉडी में डाल देता है, और return निकटतम घोषित fun से संबंधित हो जाता है, यानी main से।
यदि आप केवल forEach से बाहर निकलना चाहते हैं, न कि पूरे फंक्शन से, तो लेबल (label) का उपयोग करें:
fun main() {\n val numbers = listOf(1, 2, 3, 4, 5)\n numbers.forEach loop@{\n if (it == 3) return@loop\n println(it)\n }\n println("यह लाइन चलेगी")\n}\n\n\nआउटपुट: 1 2 और यह लाइन चलेगी। लेबल loop@ कंपाइलर को बताता है: "लैम्ब्डा से बाहर निकलो, लेकिन main से नहीं"। यह मूल रूप से continue का एक एनालॉग है — हम वर्तमान इटरेशन को छोड़ देते हैं और अगले तत्व पर चले जाते हैं।