Groovy “each” kapanmasından kopabilir misiniz?


143

breakBir Groovy'den mümkün mü .each{Closure}yoksa bunun yerine klasik bir döngü mi kullanmalıyım?

Yanıtlar:


194

Hayır, bir istisna atmadan "her birini" iptal edemezsiniz. Ara vermenin belirli bir koşulda iptal edilmesini istiyorsanız muhtemelen klasik bir döngü istersiniz.

Alternatif olarak, her biri yerine bir "find" kapaması kullanabilir ve bir mola verdiğinizde true değerini döndürebilirsiniz.

Bu örnek, listenin tamamını işlemeden önce iptal edilecektir:

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
}

Baskılar

1
2
3
4
5

ancak 6 veya 7 yazdırmaz.

Ayrıca, kapanışları kabul eden özel kesme davranışıyla kendi yineleyici yöntemlerinizi yazmak gerçekten kolaydır:

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
}

Ayrıca yazdırır:

1
2
3
4
5    

3
Ayrıca kapatma için ilk boş olmayan sonucu döndüren kısa devreli bir bulma yapan bir findResult yöntemi ekleyen groovy için bir yama gönderdim. Bu yöntem, birinin erken ayrılmak isteyebileceği neredeyse tüm durumları kapsamak için kullanılabilir. Yamayı kabul edip groovy haline getirilip getirilmediğini görmek için kontrol edin (1.8 umuyorum): jira.codehaus.org/browse/GROOVY-4253
Ted Naleid

2
Bu davayı denedim: def a = [1, 2, 3, 4, 5, 6, 7, -1, -2] 1 2 3 4 5 -1 -2 döndürdü. Yani, "mola" çalışmaz.
Phat H. VU

Doğru bulma doğru seçenektir, her biri geri dönüşle asla kırılmaz
Pushkar

daha findiyi any- bir kişinin benim için çalıştığını @Michal aşağıdaki diğer cevap bakın
Rhubarb

Ted Naleid'in harika bir yaması çok faydalıdır. Öğenin kendisinden değil, find işleminin sonucuna gerçekten ihtiyacınız varsa findResult öğesini kullanın. Örn: ​def test = [2] test.findResult{ it * 2 }​2 yerine 4 döndürecek
Doug

57

Her bir döngüyü herhangi bir kapakla değiştirin .

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

    println element

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

Çıktı

1
3

Sadece bir numara. "Aradan" sonra bir ifade varsa ne olur. Bu ifade yine de "break" dan sonra yürütülecektir.
Phat H. VU

2
@Phat H. VU Geri dönüş ekledim. "Aradan" sonra ifade yürütülmez
Michal Z muda

1
Cevabın için teşekkürler. Haklısın. Ben de cevabınızı oylarım. Daha fazla: Herhangi bir yöntem DefaultGroovyMethods içinde tanımlanır ve bir koleksiyondaki bir öğe sağlanan yüklem kapanışını karşılarsa true döndüren bir yüklem işlevidir.
Phat H. VU

any()Bu şekilde kullanmak biraz yanıltıcıdır, ancak kesinlikle işe yarar ve size kırılma veya devam etme yeteneği verir .
vegemite4me

1
@ vegemite4me gibi, bu bir "hile" olduğunu düşünüyorum ama herhangi birinin anlamını iyi anlamıyorsun. Bakım için bu çözümü kullanmamalısınız.
MatRt

11

Hayır, bir istisna atmadan Groovy'deki bir kapanıştan ayrılamazsınız. Ayrıca, kontrol akışı için istisnalar kullanmamalısınız.

Kendinizi bir kapanıştan kurtulmak istiyorsanız, muhtemelen önce bunu neden yapmak istediğinizi değil, bunu nasıl yapmak istediğinizi düşünmelisiniz. Dikkate alınması gereken ilk şey, söz konusu kapağın Groovy'nin (kavramsal) üst düzey işlevlerinden biriyle değiştirilmesi olabilir. Aşağıdaki örnek:

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

olur

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

olur

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

bu da netliğe yardımcı olur. Kodunuzun amacını çok daha iyi belirtir.

Gösterilen örneklerin potansiyel dezavantajı, yinelemenin sadece ilk örnekte erken durmasıdır. Performansla ilgili düşünceleriniz varsa, o anda ve orada durdurmak isteyebilirsiniz.

Bununla birlikte, yinelemeleri içeren çoğu kullanım durumunda genellikle Groovy'nin bulma, grep, toplama, enjekte etme, vb. Yöntemlerinden birine başvurabilirsiniz. Genellikle bir "yapılandırma" alırlar ve daha sonra sizin için yinelemenin nasıl yapılacağını "bilirler", böylece mümkünse zorunlu döngüden kaçınabilirsiniz.


1
"Hayır, bir istisna atmadan Groovy'deki bir kapanıştan ayrılamazsınız
OlliP

2

Sadece özel Kapanış kullanarak

// 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
ve 1 milyar satırınız varsa ve ilk aramada iç kapak doğru dönerse, 1 milyar eksi bir değer yinelersiniz. :(
sbglasius

-4

(1.10) .each {

eğer (o <5)

yazdır

Başka

yanlış döndür


2
Bu, kırılmaz each, sadece 4'ten büyük değerleri yazdırmaz. Bu elsegereksizdir, kodunuz onsuz da aynısını yapacaktır. Ayrıca, hemen sonra ve hemen önce koyarsanız eachkırılmadığını kanıtlayabilirsiniz . return falseprintln "not breaking"elsereturn false
Stefan van den Akker

Lütfen kodunuzu okunabilirlik açısından biçimlendirmek için en az çaba gösterin.
Mateusz

-11

Sen kırılabilirsin RETURN. Örneğin

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

Benim için çalışıyor!


6
Açıkçası kastettiği şey olmasa da, OP tam olarak sordu.
Szocske

Bunun neden olumsuz oy verdiğini açıklayabilir miyim? Bu bana +133 oyla en iyi cevabın söylediği (daha az açıklama ile) aynı kavram gibi görünüyor.
Skepi

1
@Skepi Kapatmanın üstünde "kırılamaz". anyDöndürerek dizinin yöntemini kırabilirsiniz false. Sen bozamam eachaynı şekilde yöntemini.
Nux
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.