2009-08-26 26 views

Trả lời

8

Bạn có thể ném một ngoại lệ:

try { 
    [1, 2, 3].each { 
     println(it) 
     if (it == 2) 
      throw new Exception("return from closure") 
    } 
} catch (Exception e) { } 

Sử dụng cũng có thể sử dụng "FindAll" hoặc "grep" để lọc ra danh sách của bạn và sau đó sử dụng "mỗi ".

[1, 2, 3].findAll{ it < 3 }.each{ println it } 
+8

Bạn sẽ không đồng ý rằng việc sử dụng Ngoại lệ để kiểm soát các hoạt động lưu lượng thường được coi là lựa chọn không tốt hoặc có mùi mã? –

+1

Có. Nhưng đó là một cách để thoát khỏi việc đóng cửa. Tất nhiên, thường có nhiều phương pháp thích hợp hơn như tìm hoặc findAll. –

12

12/05/2013 Đã chỉnh sửa nhiều.

Trả lời câu hỏi đã được hỏi.

Có thể thoát khỏi Đóng cửa không?

Bạn có thể "ngắt" ngoài việc đóng bằng cách phát hành từ khóa return. Tuy nhiên điều đó không hữu ích trong ví dụ được đưa ra. Lý do cho việc này là việc đóng cửa (coi nó như là một phương pháp) được gọi bởi phương thức each cho mọi mục trong bộ sưu tập.

Nếu bạn chạy ví dụ này, bạn sẽ thấy nó sẽ in 1 sau đó 3.

[1, 2, 3].each { 
    if (it == 2) return 
    println(it) 
} 

Tại sao break trong bối cảnh each không có ý nghĩa.

Để hiểu tại sao bạn không thể thoát ra khỏi phương pháp each như bạn có thể thoát ra khỏi vòng lặp for, bạn cần phải hiểu một chút về những gì đang thực sự xảy ra. Đây là cách đơn giản hóa tổng thể phương thức của từng bộ sưu tập.

myEach([0,1,3]) 

void myEach(List things) { 
    for (i in things) { 
     myEachMethod(i) 
    } 
} 

void myEachMethod(Object it) { // this is your Closure 
    if(it == 2) return 
    println it 
} 

Như bạn có thể thấy việc đóng cửa về cơ bản là một phương pháp có thể được truyền đi. Cũng giống như trong java bạn không thể đột nhập từ bên trong cuộc gọi phương thức hoặc đóng.

Việc cần làm thay vì vi phạm từ each.

Trong Groovy, bạn được yêu cầu thể hiện mã của mình bằng cách sử dụng các phép trừu tượng mức cao vì vòng lặp nguyên thủy như vậy không phải là thành ngữ. Đối với ví dụ mà bạn đã cho tôi sẽ xem xét việc sử dụng findAll. Ví dụ:

[1,2,3].findAll { it < 2 }.each { println it } 

Tôi hy vọng điều này sẽ giúp bạn hiểu những gì đang diễn ra.

Trả lời câu hỏi ngụ ý.

Bạn có thể thoát ra khỏi vòng lặp Collection.each chống lại việc đóng cửa được cung cấp của mình không?

Bạn không thể thoát ra khỏi phương thức each mà không cần phải ném và bắt ngoại lệ như John Wagenleitner đã nói. Mặc dù tôi sẽ cho rằng việc ném và bắt một ngoại lệ trong tên của kiểm soát dòng chảy là một mùi mã và một lập trình viên đồng nghiệp có thể tát tay bạn.

+0

Bản in mã số 1, 2, 3 - trả về của bạn sẽ không trả về từ lần đóng. –

+1

Chỉ muốn làm rõ rằng trở lại sẽ không "phá vỡ" ra khỏi đóng cửa, nó sẽ chỉ trả lại phương pháp thực hiện việc đóng cửa. Trong trường hợp trên, đã có một println dưới sự trở lại nó chỉ có thể in cho 1 và 3, tuy nhiên 1, 2 và 3 vẫn sẽ được in bởi println đầu tiên. –

+0

Tôi nghĩ bạn đang bối rối. "mỗi" là một PHƯƠNG PHÁP mà có một đóng cửa như là một đối số. Sau đó, lặp qua bộ sưu tập gọi đóng của bạn và đi qua trong đối tượng hiện tại như một đối số cho việc đóng. Tôi đã cập nhật câu trả lời của mình để làm cho điều này rõ ràng hơn. –

21

Tôi thường quên rằng Groovy thực hiện phương thức "bất kỳ".

[1, 2, 3].any 
{ 
    println it 
    return (it == 2) 
}​ 
2

Điều này hỗ trợ câu trả lời của John Wagenleiter. Câu trả lời của Tigerizzy là sai. Nó có thể dễ dàng được bác bỏ bằng thực thi mẫu mã đầu tiên của ông, hoặc về mặt lý thuyết bằng cách đọc tài liệu Groovy. A return trả về một giá trị (hoặc null không có đối số) từ lần lặp hiện tại, nhưng không dừng lặp lại. Trong một đóng cửa, nó hoạt động khá giống như tiếp tục.

Bạn sẽ không thể sử dụng tiêm mà không hiểu điều này.

Không có cách nào để 'ngắt vòng lặp' ngoại trừ bằng cách ném ngoại lệ. Sử dụng ngoại lệ cho mục đích này được coi là có mùi. Vì vậy, giống như Wagenleiter gợi ý, cách tốt nhất là lọc ra các phần tử bạn muốn lặp lại trước khi khởi chạy mỗi hoặc một trong các người anh em họ của nó.

7

Cố gắng sử dụng bất kỳ thay vì mỗi

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

Kết quả: 1, 2, 3

1

Chỉ cần sử dụng Closure đặ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 
} 
0

Với rx-java bạn có thể biến đổi một lần lặp lại thành obse rvable.

Sau đó, bạn có thể thay thế tiếp tục với một lọcnghỉ với takeWhile

Dưới đây là một ví dụ:

import rx.Observable 

Observable.from(1..100000000000000000) 
      .filter { it % 2 != 1} 
      .takeWhile { it<10 } 
      .forEach {println it} 
2

Có một giải pháp khác. Mặc dù, những thứ hấp dẫn như mỗi/tìm/bất kỳ là khá mát mẻ: nếu nó không phù hợp, không sử dụng nó. Bạn vẫn có thể sử dụng đồng bằng cũ

for (def element : list) 

Đặc biệt, nếu bạn cũng muốn rời khỏi phương pháp. Bây giờ bạn được tự do sử dụng tiếp tục/break/return như bạn muốn. Mã kết quả có thể không được mát mẻ, nhưng nó rất dễ hiểu và dễ hiểu.

+0

Tôi muốn đi xa hơn: sử dụng giải pháp đơn giản nhất có thể trừ khi bạn có thể thấy lý do tại sao không. Nếu bạn siêu thông thạo trong Groovy, bạn có thể tìm thấy bằng cách sử dụng 'any' ở đây với' return true' để đơn giản như thế này. Nhưng điểm đóng cửa là chúng được thiết kế để được truyền đi và điều khiển. Đối với một công việc đơn giản, một công cụ đơn giản cũ sẽ làm tốt! –

Các vấn đề liên quan