คุณช่วยแบ่งจากการปิด Groovy“ แต่ละ”?


คำตอบ:


194

ไม่คุณไม่สามารถยกเลิก "แต่ละคน" ได้โดยไม่ต้องทำการยกเว้น คุณอาจต้องการวนรอบแบบคลาสสิกหากคุณต้องการหยุดพักเพื่อยกเลิกภายใต้เงื่อนไขเฉพาะ

หรือคุณสามารถใช้การปิด "ค้นหา" แทนการปิดแต่ละรายการและคืนค่าจริงเมื่อคุณหยุดพัก

ตัวอย่างนี้จะยกเลิกก่อนที่จะประมวลผลรายการทั้งหมด:

def a = [1, 2, 3, 4, 5, 6, 7]

a.find { 
    if (it > 5) return true // break
    println it  // do the stuff that you wanted to before break
    return false // keep looping
}

พิมพ์

1
2
3
4
5

แต่ไม่พิมพ์ 6 หรือ 7

นอกจากนี้ยังง่ายมากในการเขียนวิธีการวนซ้ำของคุณเองด้วยพฤติกรรมการพักแบบกำหนดเองที่ยอมรับการปิด:

List.metaClass.eachUntilGreaterThanFive = { closure ->
    for ( value in delegate ) {
        if ( value  > 5 ) break
        closure(value)
    }
}

def a = [1, 2, 3, 4, 5, 6, 7]

a.eachUntilGreaterThanFive {
    println it
}

พิมพ์ด้วย:

1
2
3
4
5    

3
ฉันยังส่งแพตช์ไปยัง groovy ที่เพิ่มวิธี findResult ที่จะค้นหาการลัดวงจรที่ส่งกลับผลลัพธ์ไม่ใช่ non-null แรกจากการปิด วิธีนี้สามารถใช้เพื่อครอบคลุมเกือบทุกสถานการณ์ที่บางคนอาจต้องการแยกออกจากกันก่อน ตรวจสอบแพตช์เพื่อดูว่ามันได้รับการยอมรับและรีดเป็น Groovy (ฉันหวัง 1.8): jira.codehaus.org/browse/GROOVY-4253
Ted

2
ฉันได้ลองกรณีนี้: def a = [1, 2, 3, 4, 5, 6, 7, -1, -2] มันกลับมา 1 2 3 4 5 -1 -2 ดังนั้น "breaK" จึงไม่ทำงาน
Phat H. VU

การค้นหาที่ถูกต้องเป็นตัวเลือกที่ถูกต้องซึ่งจะไม่มีวันแตกหักโดยกลับ
Pushkar

คือfindดีกว่าany- ดูคำตอบอื่น ๆ ด้านล่างจาก @Michal ที่หนึ่งงานสำหรับฉัน
Rhubarb

แพทช์ของ Ted Naleid ไปยัง groovy นั้นมีประโยชน์มาก ใช้ findResult แทนหากคุณต้องการผลลัพธ์จากการดำเนินการค้นหาไม่ใช่องค์ประกอบ เช่น​def test = [2] test.findResult{ it * 2 }​จะกลับ 4 แทน 2
ดั๊ก

57

แทนที่แต่ละวงด้วยการปิดใด ๆ

def list = [1, 2, 3, 4, 5]
list.any { element ->
    if (element == 2)
        return // continue

    println element

    if (element == 3)
        return true // break
}

เอาท์พุต

1
3

เป็นแค่กลลวง จะเกิดอะไรขึ้นถ้ามีคำสั่งหลังจาก "หยุด" คำสั่งนี้จะยังคงมีอยู่หลังจากพบ "หยุด"
Phat H. VU

2
@Phat H. VU ฉันได้เพิ่มผลตอบแทน คำสั่งหลังจาก "หยุด" จะไม่ถูกดำเนินการ
Michal Z muda

1
ขอบคุณสำหรับการตอบกลับของคุณ. คุณถูก. ฉันยังโหวตคำตอบของคุณ เพิ่มเติม: เมธอดใด ๆ ถูกกำหนดใน DefaultGroovyMethods และเป็นฟังก์ชันเพรดิเคตที่คืนค่าจริงหากองค์ประกอบในคอลเลกชันเป็นไปตามการปิดเพรดิเคตที่ให้มา
Phat H. VU

การใช้any()วิธีนี้เป็นสิ่งที่ทำให้เข้าใจผิดเล็กน้อย แต่ก็สามารถใช้งานได้และทำให้คุณสามารถทำลายหรือทำต่อไปได้
vegemite4me

1
เช่น @ vegemite4me ฉันคิดว่านี่เป็น "เคล็ดลับ" แต่คุณไม่เข้าใจความหมายของคำใด ๆ เพื่อการบำรุงรักษาคุณไม่ควรใช้วิธีนี้
MatRt

11

ไม่คุณไม่สามารถหยุดพักจากการหยุดเล่นใน Groovy ได้โดยไม่ต้องทำการยกเว้น นอกจากนี้คุณไม่ควรใช้ข้อยกเว้นสำหรับโฟลว์การควบคุม

หากคุณพบว่าตัวเองต้องการแยกจากการปิดคุณควรคิดก่อนว่าทำไมคุณถึงต้องการทำสิ่งนี้และไม่ใช่วิธีการทำ สิ่งแรกที่ควรพิจารณาคือการทดแทนการปิดในคำถามด้วยหนึ่งในฟังก์ชันลำดับที่สูงขึ้นของ Groovy (แนวคิด) ตัวอย่างต่อไปนี้:

for ( i in 1..10) { if (i < 5) println i; else return}

กลายเป็น

(1..10).each{if (it < 5) println it}

กลายเป็น

(1..10).findAll{it < 5}.each{println it} 

ซึ่งยังช่วยให้ชัดเจน มันระบุเจตนาของรหัสของคุณได้ดีขึ้นมาก

ข้อเสียเปรียบที่อาจเกิดขึ้นในตัวอย่างที่แสดงคือการวนซ้ำจะหยุดก่อนในตัวอย่างแรกเท่านั้น หากคุณมีข้อควรพิจารณาเกี่ยวกับประสิทธิภาพคุณอาจต้องการหยุดมันทันที

อย่างไรก็ตามสำหรับกรณีการใช้งานส่วนใหญ่ที่เกี่ยวข้องกับการทำซ้ำคุณมักจะใช้วิธีการค้นหาอย่างใดอย่างหนึ่งของ Groovy, grep, รวบรวม, inject, ฯลฯ พวกเขามักจะใช้ "การกำหนดค่า" และ "รู้" วิธีการทำซ้ำสำหรับคุณเพื่อให้คุณสามารถหลีกเลี่ยงการวนซ้ำที่จำเป็นได้ทุกที่ที่เป็นไปได้


1
"ไม่คุณไม่สามารถหยุดพักจากการปิดใน Groovy ได้โดยไม่ต้องทำการยกเว้น" นี่คือสิ่งที่ Scala ทำดูที่dev.bizo.com/2010/01/scala-supports-non-local-returns.html
OlliP

2

เพียงแค่ใช้การปิดแบบพิเศษ

// declare and implement:
def eachWithBreak = { list, Closure c ->
  boolean bBreak = false
  list.each() { it ->
     if (bBreak) return
     bBreak = c(it)
  }
}

def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
  if (it > 3) return true // break 'eachWithBreak'
  println it
  return false // next it
}

3
และถ้าคุณมี 1 พันล้านแถวและการปิดด้านในส่งกลับค่าจริงในการโทรครั้งแรกคุณจะทำซ้ำมากกว่า 1 พันล้านลบหนึ่งค่า :(
sbglasius

-4

(1..10) .each {

ถ้า (มัน <5)

ปริ้นมัน

อื่น

กลับเท็จ


2
สิ่งนี้ไม่ได้แยกออกจากeachกัน แต่ก็ไม่ได้พิมพ์ค่าที่มากกว่า 4 ซึ่งelseไม่จำเป็นเลยรหัสของคุณจะทำแบบเดียวกันหากไม่มีมัน นอกจากนี้คุณยังสามารถพิสูจน์ได้eachไม่ทำลายด้วยreturn falseถ้าคุณใส่println "not breaking"หลังและก่อนelse return false
Stefan van den Akker

โปรดพยายามอย่างน้อยที่สุดในการจัดรูปแบบโค้ดของคุณเพื่อให้สามารถอ่านได้ มีตัวอย่างเป็นภาพเมื่อคุณตอบกลับและมีคำแนะนำมากมายให้ทำ
Mateusz คือ

-11

RETURNคุณสามารถทำลายโดย ตัวอย่างเช่น

  def a = [1, 2, 3, 4, 5, 6, 7]
  def ret = 0
  a.each {def n ->
    if (n > 5) {
      ret = n
      return ret
    }
  }

มันใช้งานได้สำหรับฉัน!


6
ซึ่งเป็นสิ่งที่ OP ต้องการแม้ว่าจะไม่ชัดเจนว่าเขาหมายถึงอะไร
Szocske

ฉันขอคำอธิบายได้ไหมว่าทำไมเรื่องนี้ถึงมีคะแนนลบ นี่เป็นแนวคิดเดียวกับที่ฉันคิดว่าคำตอบยอดนิยม (มีคำอธิบายน้อยกว่า) ด้วยคะแนนโหวต +133
Skepi

1
@Skepi คุณไม่สามารถ "หยุด" ข้างบนปิด คุณสามารถแบ่งวิธีการของอาร์เรย์โดยกลับany falseคุณไม่สามารถแยกeachวิธีด้วยวิธีเดียวกันได้
Nux
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.