कोटलिन में `forEach` में` ब्रेक` और `जारी`


120

Kotlin की तरह, बहुत अच्छा है बार-बार दोहराना कार्य करता है forEachया repeatहै, लेकिन मैं करने के लिए सक्षम नहीं कर रहा हूँ breakऔर continueऑपरेटरों उनके साथ काम (दोनों स्थानीय और गैर स्थानीय):

repeat(5) {
    break
}

(1..5).forEach {
    continue@forEach
}

लक्ष्य के रूप में यह हो सकता है के रूप में कार्यात्मक वाक्यविन्यास के साथ सामान्य छोरों की नकल करना है। कोटलिन के कुछ पुराने संस्करणों में यह निश्चित रूप से संभव था, लेकिन मैं वाक्य रचना को पुन: पेश करने के लिए संघर्ष करता हूं।

समस्या लेबल (M12) के साथ एक बग हो सकती है, लेकिन मुझे लगता है कि पहले उदाहरण को वैसे भी काम करना चाहिए।

ऐसा लगता है कि मैंने एक विशेष ट्रिक / एनोटेशन के बारे में कहीं पढ़ा है, लेकिन मुझे इस विषय पर कोई संदर्भ नहीं मिला। निम्नलिखित की तरह लग सकता है:

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
    for (index in 0..times - 1) {
        body(index)
    }
}

1
वर्तमान कोटलिन में आप वास्तव में इस की नकल कर सकते हैं ( continue@labelऔर break@labelसुविधाओं के लिए प्रतीक्षा करते हुए ), संबंधित प्रश्न देखें: stackoverflow.com/questions/34642868/…
Jayson Minard

1
यह प्रश्न इस स्पष्टीकरण का उपयोग कर सकता है कि क्या आप केवल breakऔर केवल continueकार्यात्मक छोरों की मौजूदगी के बारे में पूछ रहे हैं , या यदि आप वैकल्पिक उत्तर मांग रहे हैं, जो बिल्कुल वही काम करते हैं। पूर्व मामला प्रतीत होता है, क्योंकि आपने बाद को अस्वीकार कर दिया था।
जैसन मिनार्ड

ऐसा लगता है कि उन्हें कहा जाता है कि कोटलिन 1.3 में
तिगरान बाबजयान 7

@TigranBabajanyan वाह! क्या आपके पास एक लिंक है?
वोड्डन

@ वोड्डन, नहीं, मैंने अभी-अभी यह कोशिश की है
तिगरान बाबजयान

जवाबों:


69

संपादित करें :
कोटलिन के प्रलेखन के अनुसार , एनोटेशन का उपयोग करना संभव है।

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
        print(it)
    }
    print(" done with explicit label")
}

मूल उत्तर :
चूंकि आप सप्लाई करते हैं (Int) -> Unit, आप इससे नहीं टूट सकते, क्योंकि कंपाइलर को यह पता नहीं है कि इसका उपयोग लूप में किया जाता है।

आपके पास कुछ विकल्प हैं:

लूप के लिए एक नियमित उपयोग करें:

for (index in 0 until times) {
    // your code here
}

यदि लूप विधि में अंतिम कोड है
आपreturn से बाहर निकलने के लिए उपयोग कर सकते हैं (या return valueयदि यह unitविधि नहीं है)।

एक विधि का उपयोग
करें एक कस्टम रिपीट विधि विधि बनाएं जो Booleanनिरंतर जारी रहे।

public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
    for (index in 0 until times) {
        if (!body(index)) break
    }
}

वास्तव में, मेरा प्रश्न विशेष सिंटैक्स कार्य करने के बारे में था, न कि पुनरावृत्ति के बारे में। क्या आपको याद नहीं है कि यह कुछ कोटलिन मील के पत्थर पर संभव था?
वोड्डन

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

1
breakऔर continueकेवल लूप में काम करते हैं। forEach, repeatऔर अन्य सभी विधियाँ बस यही हैं: विधियाँ और लूप नहीं। Yoav कुछ विकल्प प्रस्तुत लेकिन breakऔर continueसिर्फ तरीकों के लिए काम करने के लिए बयान नहीं कर रहे हैं।
किरिल रहमान

@ यवसर्नबर्ग ब्रिलियंट! यह पुराने डॉक्स की शांति है जिसकी मुझे तलाश थी! इसलिए इस सुविधा को अभी तक लागू नहीं किया गया है, भविष्य के संस्करणों के लिए छोड़ दिया गया है। यदि आप एक अलग जवाब बनाने के लिए परवाह करते हैं, तो मैं इसे चिह्नित
करूंगा

वर्तमान कोटलिन में आप वास्तव में इसकी नकल कर सकते हैं ( continue@labelऔर break@labelसुविधाओं के लिए प्रतीक्षा करते हुए ), संबंधित प्रश्न देखें: stackoverflow.com/questions/34642868/…
Jayson Minard

104

यह 1 से 5 तक प्रिंट करेगा। जावा में return@forEachकीवर्ड की तरह कार्य करता है continue, जिसका अर्थ है कि इस मामले में, यह अभी भी हर लूप को निष्पादित करता है लेकिन मान 5 से अधिक होने पर अगले पुनरावृत्ति पर छोड़ देता है।

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it > 5) return@forEach
       println(it)
    }
}

यह 1 से 10 प्रिंट करेगा, लेकिन 5 को छोड़ देगा।

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it == 5) return@forEach
       println(it)
    }
}

उन्हें कोटलिन खेल के मैदान में आज़माएं ।


महान, लेकिन यह अभी भी कुछ शर्त पूरी होने पर समय से पहले खत्म करने में सक्षम नहीं होने की समस्या का समाधान नहीं करता है। यह अभी भी लूप निष्पादित करता रहता है।
13

1
@ फ़ॉक्स हाँ, यह हर लूप को निष्पादित करता है और जब शर्त पूरी हो जाती है तो वापसी के बाद कुछ भी छोड़ देता है। फ़ोरच में प्रत्येक ऑपरेशन एक लैम्ब्डा फ़ंक्शन है, वर्तमान में फ़ोरच ऑपरेशन के लिए कोई सटीक ब्रेक ऑपरेशन नहीं है। ब्रेक छोरों के लिए उपलब्ध है, देखें: kotlinlang.org/docs/reference/returns.html
s-hunter

यहाँ दोनों के साथ एक चंचल कोटलिन खेल का मैदान स्निपेट है continueऔर breakउदाहरण: pl.kotl.in/_LAvET-wX
ashughes

34

एक ब्रेक का उपयोग करके प्राप्त किया जा सकता है:

//Will produce"12 done with nested loop"
//Using "run" and a tag will prevent the loop from running again. Using return@forEach if I>=3 may look simpler, but it will keep running the loop and checking if i>=3 for values >=3 which is a waste of time.
fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // non-local return from the lambda passed to run
            print(it)
        }
    }
    print(" done with nested loop")
}

और जारी रखा जा सकता है:

//Will produce: "1245 done with implicit label"
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
        print(it)
    }
    print(" done with implicit label")
}

जैसा कि यहां कोई भी सुझाता है ... डॉक्स पढ़ें: P https://kotlinlang.org/docs/reference/returns.html#return-at-labels


अच्छा समाधान है। बहुत अच्छा काम करता है। हालांकि ऐसा लगता है कि बिना उपयोग @loopके भी वांछित परिणाम देता है।
पारस सिद्धू

वास्तव में, आप स्पष्ट टैग "@ लूप" को छोड़ सकते हैं और निहित "@ क्रून" का उपयोग कर सकते हैं। यहाँ का मुख्य पहलू लैम्बडा के कॉलर के लिए स्थानीय वापसी है। ध्यान दें कि आपको लूप को कुछ दायरे में लपेटने की आवश्यकता है ताकि आप बाद में इस पर स्थानीय रिटर्न पा सकें।
रेमंड आर्टिगा

28

आप लैम्ब्डा एक्सप्रेशन से रिटर्न का उपयोग कर सकते हैं जो continueया तो नकल करता हैbreak निर्भर करता है आपके उपयोग की।

यह संबंधित प्रश्न में शामिल है: कोटलिन के भीतर एक कार्यात्मक लूप में मैं "ब्रेक" या "जारी" कैसे कर सकता हूं?


17

जैसा कि कोटलिन दस्तावेज़ीकरण कहता है , उपयोग returnकरना जाने का तरीका है। कोटलिन के बारे में अच्छी बात यह है कि यदि आपके पास नेस्टेड फ़ंक्शन हैं, तो आप एक्सप्लिसिटी को लिखने के लिए लेबल का उपयोग कर सकते हैं जहां से आपका रिटर्न है:

कार्यक्षेत्र वापसी

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach {
    if (it == 3) return // non-local return directly to the caller of foo()
    print(it)
  }
  println("this point is unreachable")
}

और स्थानीय रिटर्न (यह forEach = निरंतरता से गुजरना बंद नहीं करता है)

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach lit@{
    if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
    print(it)
  }
  print(" done with explicit label")
}

प्रलेखन की जाँच करें, यह वास्तव में अच्छा है :)


3
चेतावनी: रिटर्न @ लिट बंद नहीं होता हैforEach
Jemshit Iskenderov

वह सही है। यह इरादा है। पहला समाधान यह करता है, लेकिन यदि आपके पास एक लूप के अंदर निर्देश हैं, तो आप चुन सकते हैं कि आप कहाँ / वापस लौटना चाहते हैं। दूसरे मामले में, यदि हम सिर्फ रिटर्न का उपयोग करते हैं तो यह बंद हो जाएगा ;-)
cesards

कॉलिंग रिटर्न @ लिट पसंद जारी है
pqtuan86

10

continue में व्यवहार टाइप करें forEach

list.forEach { item -> // here forEach give you data item and you can use it 
    if () {
        // your code
        return@forEach // Same as continue
    }

    // your code
}

के लिए breakप्रकार व्यवहार आप उपयोग करने के लिए है for in untilया for inके रूप में प्रति सूची है NullableयाNon-Nullable

  1. के लिए Nullable सूची:

    for (index in 0 until list.size) {
        val item = list[index] // you can use data item now
        if () {
            // your code
            break
        }
    
        // your code
    }
  2. के लिए गैर-व्यर्थ सूची:

    for (item in list) { // data item will available right away
        if () {
            // your code
            break
        }
    
        // your code
    }

2

नेस्टेड छोरों के लिए ब्रेक स्टेटमेंट फॉर ():

listOf("a", "b", "c").forEach find@{ i ->
    listOf("b", "d").forEach { j ->
        if (i == j) return@find
        println("i = $i, j = $j")
    }
}

परिणाम:

i = a, j = b
i = a, j = d
i = c, j = b
i = c, j = d

अनाम फ़ंक्शन के साथ जारी रखें कथन:

listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
    if (value == 3) return
    print("$value ")
})

परिणाम:

1 2 4 5 

0

शायद आगे के लिए बदल जाते हैं

for(it in myList){
   if(condition){
     doSomething()
   }else{
     break //or continue
    }
} 

यह हैशमैप के लिए काम करता है

 for(it in myMap){
     val k = it.key
     val v = it.value

       if(condition){
         doSomething()
       }else{
         break //or continue
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.