Groovyの「各」クロージャーから脱却できますか?


143

breakGroovyから取得することは可能.each{Closure}ですか、それとも代わりにクラシックループを使用する必要がありますか?

回答:


194

いいえ、例外をスローせずに「各」を中止することはできません。特定の条件下でブレークを中止したい場合は、クラシックループが必要になる可能性があります。

または、それぞれの代わりに「検索」クロージャを使用して、ブレークを実行したときにtrueを返すこともできます。

この例は、リスト全体を処理する前に中止されます。

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
また、クロージャーから最初のnull以外の結果を返す短絡検索を実行するfindResultメソッドを追加するパッチをgroovyに送信しました。この方法は、誰かがそれぞれの状況から早期に脱出したいと思う可能性のあるほとんどすべての状況をカバーするために使用できます。パッチが受け入れられ、groovyに組み込まれるかどうかを確認します(1.8を期待しています): jira.codehaus.org/browse/GROOVY-4253
Ted Naleid

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からの私のための1つの作品
ルバーブ

Ted Naleidのgroovyへのパッチは非常に便利です。要素自体ではなく、検索操作の結果が実際に必要な場合は、代わりにfindResultを使用します。例:​def test = [2] test.findResult{ it * 2 }​2ではなく4を返します
Doug

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

ただのトリック。「break」の後にステートメントがある場合はどうなりますか。このステートメントは、 "break"が満たされた後も実行されます。
Phat H. VU

2
@Phat H. VUリターンを追加しました。「ブレーク」後のステートメントは実行されません
ミハルZムダ

1
お返事をありがとうございます。あなたが正しい。私もあなたの答えに投票します。詳細:anyメソッドはDefaultGroovyMethodsで定義されており、コレクション内の要素が指定された述語クロージャを満たす場合にtrueを返す述語関数です。
Phat H. VU

any()この方法での使用は少し誤解を招きますが、確かに機能し、中断または続行することができます。
vegemite4me 2014年

1
@ vegemite4meのように、これは「トリック」だと思いますが、その意味をよく理解していません。保守性のため、このソリューションは使用しないでください。
MatRt 2015

11

いいえ、例外をスローせずにGroovyのクロージャーから抜け出すことはできません。また、制御フローに例外を使用しないでください。

自分がクロージャから抜け出したいと思っているのに気づいたら、おそらく最初に、なぜこれを実行したいのかを考え、どのようにそれを実行しないのかを考えるべきです。最初に検討すべきことは、問題のクロージャーをGroovyの(概念的な)高次関数の1つで置き換えることです。次の例:

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のfind、grep、collect、injectなどのメソッドのいずれかに頼ることができます。彼らは通常、いくつかの「構成」を取り、次に反復をどのように行うかを「知っている」ため、可能な限り命令ループを実際に回避することができます。


1
「いいえ、例外をスローせずにGroovyのクロージャーから抜け出す
2010/01 /

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
10億行あり、最初の呼び出しで内部クロージャーがtrueを返す場合、10億から1値を引いた値を繰り返します。:(
sbglasius

-4

(1..10).each {

if(それ<5)

println it

そうしないと

falseを返す


2
これはeach、から抜け出すことはなく、単に4より大きい値を出力しません。これelseは不必要です。コードがなければ、コードは同じように動作します。また、直後と直前に置いeachても壊れないことを証明できreturn falseます。println "not breaking"elsereturn 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 2013

なぜこれが反対票を投じているのか説明をいただけますか?これは、+ 133票で、トップの回答が言う(説明は少ない)と同じ概念です。
スケピ2017年

1
@Skepiクロージャを「ブレーク」することはできません。をany返すと、配列のメソッドを分割できfalseます。each同じ方法でメソッドを壊すことはできません。
木の実
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.