Bạn có thể thoát khỏi một Groovy vào mỗi lần đóng cửa không?


143

Có thể breaktừ Groovy .each{Closure}, hoặc tôi nên sử dụng một vòng lặp cổ điển thay thế?

Câu trả lời:


194

Không, bạn không thể hủy bỏ "mỗi" mà không ném ngoại lệ. Bạn có thể muốn một vòng lặp cổ điển nếu bạn muốn nghỉ để hủy bỏ trong một điều kiện cụ thể.

Ngoài ra, bạn có thể sử dụng bao đóng "tìm" thay vì mỗi lần đóng và trả về đúng khi bạn đã nghỉ.

Ví dụ này sẽ hủy bỏ trước khi xử lý toàn bộ danh sách:

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
}

Bản in

1
2
3
4
5

nhưng không in 6 hoặc 7.

Thật dễ dàng để viết các phương thức lặp của riêng bạn với hành vi ngắt tùy chỉnh chấp nhận các bao đóng:

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
}

Cũng in:

1
2
3
4
5    

3
Tôi cũng đã gửi một bản vá cho Groovy có thêm phương thức findResult thực hiện một phát hiện ngắn mạch trả về kết quả không null đầu tiên từ việc đóng. Phương pháp này có thể được sử dụng để bao quát hầu hết tất cả các tình huống mà ai đó có thể muốn thoát ra khỏi từng trường hợp sớm. Kiểm tra bản vá để xem nó có được chấp nhận và chuyển thành Groovy không (tôi hy vọng là 1.8): jira.codehaus.org/browse/GROOVY-4253
Ted Naleid

2
Tôi đã thử trường hợp này: def a = [1, 2, 3, 4, 5, 6, 7, -1, -2] Nó trả về 1 2 3 4 5 -1 -2. Vì vậy, "breaK" không hoạt động.
Phát H. VU

Tìm đúng là tùy chọn chính xác, mỗi tùy chọn sẽ không bao giờ bị phá vỡ bằng cách quay lại
Pushkar

findtốt hơn so với any- xem câu trả lời khác dưới đây từ @Michal rằng một công trình đối với tôi
Đại hoàng

Bản vá của Ted Naleid cho Groovy rất hữu ích. Sử dụng findResult thay vào đó nếu bạn thực sự cần kết quả từ hoạt động find chứ không phải chính phần tử. Ví dụ: ​def test = [2] test.findResult{ it * 2 }​sẽ trả về 4 thay vì 2
Doug

57

Thay thế mỗi vòng lặp với bất kỳ đóng cửa.

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

    println element

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

Đầu ra

1
3

Chỉ là một mánh khóe. Điều gì xảy ra nếu có một tuyên bố sau khi "phá vỡ". Tuyên bố này sẽ vẫn được thực hiện sau khi gặp "phá vỡ".
Phát H. VU

2
@Phat H. VU Tôi đã thêm trở lại. Tuyên bố sau khi "phá vỡ" sẽ không được thực thi
Michal Z muda 7/12/13

1
Cảm ơn vì đã trả lời. Bạn đúng. Tôi cũng bỏ phiếu lên câu trả lời của bạn. Hơn nữa: bất kỳ phương thức nào được định nghĩa trong DefaultGroovyMethods và nó là một hàm vị ngữ trả về true nếu một phần tử trong tập hợp thỏa mãn bao đóng vị ngữ được cung cấp.
Phát H. VU

Sử dụng any()theo cách này là một chút sai lệch, nhưng nó chắc chắn có tác dụng và cung cấp cho bạn khả năng phá vỡ hoặc tiếp tục .
vegemite4me

1
như @ vegemite4me, tôi nghĩ đây là một "mánh khóe" nhưng bạn không hiểu rõ ý nghĩa của bất kỳ. Để bảo trì, bạn không nên sử dụng giải pháp này.
MatRt

11

Không, bạn không thể thoát khỏi việc đóng cửa trong Groovy mà không ném ngoại lệ. Ngoài ra, bạn không nên sử dụng ngoại lệ cho luồng điều khiển.

Nếu bạn thấy mình muốn thoát ra khỏi sự đóng cửa, trước tiên bạn có thể nên nghĩ về lý do tại sao bạn muốn làm điều này chứ không phải làm thế nào để làm điều đó. Điều đầu tiên cần xem xét có thể là sự thay thế của bao đóng trong câu hỏi bằng một trong các hàm bậc cao hơn (khái niệm) của Groovy. Ví dụ sau:

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

trở thành

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

trở thành

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

Điều này cũng giúp rõ ràng. Nó nêu ý định của mã của bạn tốt hơn nhiều.

Hạn chế tiềm năng trong các ví dụ được hiển thị là việc lặp lại chỉ dừng lại sớm trong ví dụ đầu tiên. Nếu bạn có những cân nhắc về hiệu suất, bạn có thể muốn dừng nó ngay lúc đó và ở đó.

Tuy nhiên, đối với hầu hết các trường hợp sử dụng liên quan đến các lần lặp, bạn thường có thể sử dụng một trong các phương pháp tìm, grep, thu thập, tiêm, v.v. của Groovy. Họ thường lấy một số "cấu hình" và sau đó "biết" cách thực hiện phép lặp cho bạn, để bạn thực sự có thể tránh vòng lặp bắt buộc bất cứ khi nào có thể.


1
"Không, bạn không thể thoát khỏi sự đóng cửa trong Groovy mà không đưa ra một ngoại lệ." Đây là những gì Scala làm, xem dev.bizo.com/2010/01/scala-supports-non-local-returns.html
OlliP

2

Chỉ cần sử dụng đóng cửa đặc biệt

// 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
và nếu bạn có 1 tỷ hàng và kết thúc bên trong trả về đúng trong cuộc gọi đầu tiên, thì bạn sẽ lặp lại hơn 1 tỷ trừ đi một giá trị. :(
sbrebius

-4

(1..10) .each {

nếu (nó <5)

in nó

khác

trả lại sai


2
Điều này không thoát ra khỏi each, nó chỉ đơn giản là không in các giá trị lớn hơn 4. Điều elsenày là thừa, mã của bạn sẽ làm như vậy mà không có nó. Ngoài ra, bạn có thể chứng minh eachkhông phá vỡ return falsenếu bạn đặt println "not breaking"ngay sau elsevà ngay trước đó return false.
Stefan van den Akker

Vui lòng thực hiện ít nhất nỗ lực tối thiểu để định dạng mã của bạn để dễ đọc. Có một bản xem trước trực quan khi bạn trả lời và rất nhiều hướng dẫn cách thực hiện
Mateusz là

-11

Bạn có thể vượt qua RETURN. Ví dụ

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

Nó làm việc cho tôi!


6
Đó chính xác là những gì OP yêu cầu, mặc dù rõ ràng đó không phải là ý anh.
Szocske

Tôi có thể có một mô tả tại sao điều này có phiếu bầu tiêu cực. Đây dường như là khái niệm giống như những gì câu trả lời hàng đầu nói (với ít lời giải thích hơn) với +133 phiếu bầu.
Skepi

1
@Skepi Bạn không thể "phá vỡ" trên đóng cửa. Bạn có thể phá vỡ anyphương thức của mảng bằng cách trả về false. Bạn không thể phá vỡ eachphương thức theo cùng một cách.
Nux
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.