2012-07-02 39 views
35

Sự khác biệt giữa IteratorIterable trong scala là gì?Quan hệ giữa Iterable và Iterator là gì?

Tôi nghĩ rằng Iterable đại diện cho một tập hợp mà tôi có thể lặp lại và Iterator là một "con trỏ" tới một trong các mục trong tập hợp có thể lặp lại.

Tuy nhiên, Iterator có các chức năng như forEach, map, foldLeft. Nó có thể được chuyển đổi thành Iterable qua toIterable. Và, ví dụ: scala.io.Source.getLines trả về Iterator, không phải Iterable.

Nhưng tôi không thể làm groupBy trên Iterator và tôi có thể làm điều đó trên Iterable.

Vậy, mối quan hệ giữa hai số này, IteratorIterable là gì?

Trả lời

50

Tóm lại: An Iterator không có trạng thái, trong khi Iterable thì không.

Xem tài liệu API cho cả hai.

Iterable:

Một đặc điểm cơ sở cho các bộ sưu tập iterable.

Đây là đặc điểm cơ bản cho tất cả các bộ sưu tập Scala xác định phương thức lặp để từng bước một từng phần tử của tập hợp. [...] Tính trạng này thực hiện phương pháp foreach của Iterable bằng cách bước thông qua tất cả các phần tử sử dụng trình lặp.

Iterator:

vòng lặp là các cấu trúc dữ liệu cho phép để lặp qua một chuỗi các yếu tố . Chúng có phương thức hasNext để kiểm tra xem có một phần tử tiếp theo là và phương thức tiếp theo trả về phần tử tiếp theo và loại bỏ nó khỏi trình vòng lặp hay không.

Trình lặp có thể thay đổi: hầu hết các thao tác trên nó đều thay đổi trạng thái của nó. Trong khi nó thường được sử dụng để lặp qua các phần tử của một bộ sưu tập, nó cũng có thể được sử dụng mà không được hỗ trợ bởi bất kỳ bộ sưu tập nào (xem hàm tạo trên đối tượng đồng hành).

Bạn có thể dừng lặp lại và tiếp tục sau này nếu muốn. Nếu bạn cố gắng làm điều này với một Iterable nó sẽ bắt đầu từ đầu một lần nữa:

scala> val iterable: Iterable[Int] = 1 to 4 
iterable: Iterable[Int] = Range(1, 2, 3, 4) 

scala> iterable.take(2) 
res8: Iterable[Int] = Range(1, 2) 

scala> iterable.take(2) 
res9: Iterable[Int] = Range(1, 2) 

scala> val iterator = iterable.iterator 
iterator: Iterator[Int] = non-empty iterator 

scala> if (iterator.hasNext) iterator.next 
res23: AnyVal = 1 

scala> if (iterator.hasNext) iterator.next 
res24: AnyVal = 2 

scala> if (iterator.hasNext) iterator.next 
res25: AnyVal = 3 

scala> if (iterator.hasNext) iterator.next 
res26: AnyVal = 4 

scala> if (iterator.hasNext) iterator.next 
res27: AnyVal =() 

Note, mà tôi đã không sử dụng take trên Iterator. Lý do cho điều này là nó là khó sử dụng. hasNextnext là hai phương pháp duy nhất được đảm bảo hoạt động như mong đợi trên Iterator.Xem lại Scaladoc:

Bạn không bao giờ nên sử dụng trình lặp sau khi gọi phương thức trên đó. Hai ngoại lệ quan trọng nhất cũng là phương pháp trừu tượng duy nhất: tiếp theo và hasNext.

Cả hai phương pháp này có thể được gọi bất kỳ số lần nào mà không cần phải hủy trình lặp. Lưu ý rằng thậm chí cóNext có thể gây ra đột biến - chẳng hạn như khi lặp lại từ luồng đầu vào, nơi nó sẽ chặn cho đến khi luồng bị đóng hoặc một số đầu vào có sẵn.

Hãy xem xét ví dụ này để sử dụng an toàn và không an toàn:

def f[A](it: Iterator[A]) = { 
    if (it.hasNext) {   // Safe to reuse "it" after "hasNext" 
    it.next     // Safe to reuse "it" after "next" 
    val remainder = it.drop(2) // it is *not* safe to use "it" again after this line! 
    remainder.take(2)   // it is *not* safe to use "remainder" after this line! 
    } else it 
} 
+1

cảm ơn, với ví dụ, nó có ý nghĩa hoàn hảo. –

+0

Odersky và Spoon đã viết một mồi tốt về các lớp thu gom Scala: xem http://www.scala-lang.org/docu/files/collections-api/collections.html –

+0

Tôi đã thử nghiệm điều này trong Scala 2.11.7, iterator hoạt động tương tự như iterable, cụ thể là, khi bạn gọi 'take (2)' lần thứ hai, bạn vẫn nhận được 'List (1, 2)'. – qed

5

Một lời giải thích từ Martin Odersky và Lex Spoon:

Có một sự khác biệt quan trọng giữa các phương pháp foreach trên lặp và cùng một phương thức trên các bộ sưu tập truyền tải được: Khi được gọi là đến một trình lặp, foreach sẽ rời khỏi trình vòng lặp ở cuối của nó khi nó được thực hiện . Vì vậy, việc gọi lại tiếp theo trên cùng một trình lặp sẽ không thành công với một số NoSuchElementException. Ngược lại, khi được gọi vào một bộ sưu tập, foreach để lại số phần tử trong bộ sưu tập không thay đổi (trừ khi hàm được truyền thêm vào để loại bỏ các phần tử, nhưng đây là không khuyến khích vì nó có thể dẫn đến kết quả đáng ngạc nhiên).

Nguồn: cũng http://www.scala-lang.org/docu/files/collections-api/collections_43.html

Note (nhờ Wei-Ching Lin cho mẹo này) Iterator mở rộng TraversableOnce đặc điểm trong khi Iterable không.

0

Cũng lưu ý (nhờ Wei-Ching Lin cho mẹo này) Iterator mở rộng đặc tính TraversableOnce TraversableOnce trong khi Iterable không.

Trong scala 2.11 cả Iterator và Itarable extends TraversableOnce trait.

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