Những lợi thế của next-iterator so với iterator này là gì?


8

Tôi không làm việc quá thường xuyên với các trình lặp Java / C # trực tiếp nhưng khi tôi làm việc, tôi luôn tự hỏi đâu là lý do để thiết kế các trình vòng lặp theo kiểu "tiếp theo".

Để bắt đầu, bạn phải di chuyển iterator, để kiểm tra xem có một số dữ liệu bạn phải kiểm tra xem có phần tử tiếp theo không.

Khái niệm hấp dẫn hơn đối với tôi là trình lặp này - nó "bắt đầu" từ đầu và bạn có thể kiểm tra trạng thái này, giả sử isValid. Vì vậy, vòng lặp trên toàn bộ bộ sưu tập sẽ như thế này:

while (iter.isValid())
{
  println(iter.current());
  iter.next();
}

Khi bạn ở đây để kiểm tra xem có phần tử tiếp theo không, bạn đến đó và sau đó bạn kiểm tra xem trạng thái có hợp lệ không.

YMMV nhưng dù sao đi nữa - có bất kỳ lợi thế nào của trình lặp tiếp theo (như trong Java / C #) so với trình lặp này không?

Lưu ý: đây là câu hỏi về khái niệm, về thiết kế của ngôn ngữ.


câu hỏi dành cho java hoặc C # bzoc phương thức isValid không tồn tại trong java

@NiksTyagi Đây là một câu hỏi về khái niệm áp dụng như nhau cho cả hai, vì thiết kế đề xuất khác với cách thực hiện của ngôn ngữ.
Phục vụ

Mỗi cuộc gọi ảo là tốn kém. Ví dụ của bạn có ba cuộc gọi, .net chỉ có hai cuộc gọi. Cá nhân tôi muốn giảm nó thành một cuộc gọi.
CodeInChaos

Câu trả lời:


6

Tôi nghĩ rằng một lợi thế của MoveNext()mô hình C # /. NET so với hasNext()mô hình của Java là trước đây ngụ ý rằng một số công việc có thể được thực hiện. Các hasNext()phương pháp ngụ ý một kiểm tra trạng thái đơn giản. Nhưng điều gì sẽ xảy ra nếu bạn đang lặp lại một luồng lười biếng và bạn phải đi ra ngoài cơ sở dữ liệu để xác định xem có kết quả nào không? Trong trường hợp đó, cuộc gọi đầu tiên hasNext()có thể là một hoạt động chặn dài. Việc đặt tên của hasNext()phương thức có thể rất sai lệch như những gì đang thực sự xảy ra.

Đối với một ví dụ trong thế giới thực, vấn đề thiết kế này làm tôi khó chịu khi triển khai các API mở rộng phản ứng (Rx) của Microsoft trong Java. Cụ thể, đối với iterator được tạo bởi IObservable.asIterable()để hoạt động đúng, hasNext()phương thức sẽ phải chặn và chờ thông báo mục / lỗi / hoàn thành tiếp theo đến. Điều đó hầu như không trực quan: tên ngụ ý kiểm tra trạng thái đơn giản. Trái ngược với thiết kế C #, nơi MoveNext()sẽ phải chặn, đây không phải là kết quả bất ngờ hoàn toàn khi bạn đang xử lý một luồng được đánh giá lười biếng.

Quan điểm của tôi là thế này: mô hình "next-iterator" thích hợp hơn mô hình "this-iterator" bởi vì mô hình "this-iterator" thường là một lời nói dối: bạn có thể được yêu cầu tìm nạp trước phần tử tiếp theo để kiểm tra trạng thái của vòng lặp. Theo tôi, một thiết kế truyền đạt khả năng đó rõ ràng là tốt hơn. Đúng, các quy ước đặt tên của Java thực hiện theo mô hình "tiếp theo", nhưng các hàm ý hành vi tương tự như các mô hình "mô hình lặp này".


Làm rõ: Có lẽ tương phản Java và C # là một lựa chọn kém, bởi vì mô hình của Java là lừa đảo. Tôi coi sự khác biệt quan trọng nhất trong các mô hình được OP trình bày là mô hình "trình lặp này" tách rời logic "hợp lệ" từ logic "truy xuất phần tử hiện tại / tiếp theo", trong khi triển khai "trình lặp tiếp theo" lý tưởng kết hợp các hoạt động này. Tôi cảm thấy thích hợp để kết hợp chúng bởi vì, trong một số trường hợp, việc xác định xem trạng thái của trình lặp có hợp lệ hay không đòi hỏi phải tìm nạp trước phần tử tiếp theo , do đó khả năng đó phải được làm rõ ràng nhất có thể.

Tôi không thấy sự khác biệt đáng kể về thiết kế giữa:

while (i.isValid()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.current()); // retrieve the element (may be slow!)
    i.next();
}
// ...and:
while (i.hasNext()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.next()); // retrieve the element (may be slow!)
}

Nhưng tôi thấy một sự khác biệt có ý nghĩa ở đây:

while (i.hasNext()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.next()); // retrieve the element (may be slow!)
}
// ...and:
while (i.moveNext()) { // fetch the next element if it exists (may be slow!)
    doSomething(i.current()); // get the element  (implied as fast, non-blocking)
}

Trong cả isValid()hasNext()ví dụ, hoạt động được ngụ ý là kiểm tra trạng thái nhanh và không chặn trên thực tế có thể là hoạt động chặn chậm . Trong moveNext()ví dụ này, hầu hết các công việc đang được thực hiện theo phương pháp bạn mong đợi, bất kể bạn đang xử lý một luồng được đánh giá háo hức hay lười biếng.


1
+0: ​​Tôi nghĩ OP đã cố so sánh Java / C # với một số trình vòng lặp khác (cả C # IEnumitable và Java Iterator đều trỏ đến các phần tử "trước" khi được tạo). Sự hiểu biết của tôi về câu hỏi là tại sao không chỉ đến yếu tố đầu tiên thay vì so sánh C # vsJava.
Alexei Levenkov

Cảm ơn bạn đã trả lời, nhưng C # và Java sử dụng cùng một mô hình (cả hai đều tập trung vào phần tử tiếp theo).
greenoldman

Các mô hình C # và Java chắc chắn không giống nhau. Xem ví dụ thêm của tôi. Mô hình của C # kết hợp các hoạt động kiểm tra sự hiện diện của một phần tử với tìm nạp phần tử đó. Java chia các hoạt động này thành các hoạt động riêng biệt, với việc kiểm tra sự hiện diện đôi khi bắt buộc phải thực sự tìm nạp vật phẩm dưới mui xe. Nó thực sự khá giống với ví dụ của OP: nếu bạn bỏ qua tên của các phương thức, hasNext()thì tương tự isValid()next()tương tự như current().
Mike Strobel

Tôi có nghĩa là mô hình trong ý nghĩa của câu hỏi NÀY . Ok, chúng không giống nhau nhưng cả hai đều dựa trên yếu tố tiếp theo, khi bạn lặp lại trong cả hai bạn phải đi đến yếu tố tiếp theo khi bắt đầu, bởi vì cả hai đều bắt đầu trước khi thu thập thực tế.
greenoldman

Tôi khẳng định rằng mô hình Java rất tương tự như "này-iterator" mô hình trong câu hỏi về cách thức nó thực sự hoạt động . Tôi khẳng định rằng các hàm ý hành vi giữa "trình lặp này" và "trình lặp tiếp theo" quan trọng hơn các quy ước đặt tên và mô hình Java có ý nghĩa hành vi tương tự như ví dụ "trình lặp này" của bạn. Mặc dù câu trả lời của tôi có thể đi lạc vào lãnh thổ, OP đã không cân nhắc khi đặt câu hỏi, tôi không nghĩ rằng điều đó làm cho câu trả lời của tôi ít có giá trị hơn.
Mike Strobel

7

Nếu có một số tính toán cần phải được thực hiện để tính toán từng giá trị phải nhận giá trị tiếp theo trước khi yêu cầu giá trị đầu tiên cho phép bạn trì hoãn việc xử lý giá trị đầu tiên đó ngoài việc xây dựng trình lặp.

Ví dụ: iterator có thể biểu thị một truy vấn chưa được thực hiện. Khi mục đầu tiên được yêu cầu, cơ sở dữ liệu được truy vấn cho kết quả. Sử dụng thiết kế được đề xuất của bạn, việc tính toán đó sẽ cần phải được thực hiện khi xây dựng trình lặp (điều này làm cho việc trì hoãn thực thi khó khăn hơn) hoặc khi gọi IsValid, trong trường hợp đó thực sự là một cách hiểu sai, vì việc gọi IsValidthực sự sẽ nhận được giá trị tiếp theo.


Câu trả lời tốt đẹp. Bạn đánh cùng điểm với tôi, nhưng đánh tôi vài giây. Có một upvote :).
Mike Strobel

1
Cảm ơn bạn đã trả lời, nhưng tôi tin rằng nó không chính xác. Để kiểm tra xem iterator có hợp lệ không, bạn không cần phải lấy phần tử thực, chỉ cần vị trí của iterator. IOW nó có tác động tương tự như hasNext, chỉ trạng thái của nó về trạng thái hiện tại, không phải là tương lai. Hoặc đưa ra một góc nhìn khác - so sánh điều này với các trình lặp C ++, bạn kiểm tra xem trạng thái có hợp lệ (current!=end)không mà không cần chạm vào dữ liệu thực tế.
greenoldman

Tái bút Hãy đưa ra kịch bản của bạn - Tôi muốn in kết quả, vì vậy tôi phải gọi hasNextkhi bắt đầu, ở đây truy vấn được thực thi, dữ liệu được lấy. Trong mô hình thứ hai, tôi gọi isValid, ở đây truy vấn được thực thi. Vì vậy, điểm của việc thực hiện truy vấn là như nhau.
greenoldman

@greenoldman Vì vậy, khi gọi IsValidnhững gì bạn thực sự đang làm là nhận được giá trị tiếp theo. Điều này có nghĩa là nó hoạt động chính xác giống như trình lặp hiện tại (nó không có giá trị hiện tại ngay từ đầu, mà không cần phải gọi một phương thức để lấy nó) nó chỉ có một tên sai.
Phục vụ

1
Chính xác. Mô hình "next-iterator" thích hợp hơn mô hình "this-iterator" bởi vì mô hình "this-iterator" thường là một lời nói dối: bạn có thể được yêu cầu tìm nạp trước phần tử tiếp theo để kiểm tra trạng thái của trình lặp .
Mike Strobel
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.