Tôi đã xem xét câu hỏi này nhưng vẫn không hiểu sự khác biệt giữa các đặc điểm Có thể duyệt và Có thể duyệt. Ai đó có thể giải thích?
Tôi đã xem xét câu hỏi này nhưng vẫn không hiểu sự khác biệt giữa các đặc điểm Có thể duyệt và Có thể duyệt. Ai đó có thể giải thích?
Câu trả lời:
Nói một cách đơn giản, các trình vòng lặp giữ trạng thái, các trình duyệt thì không.
Một Traversable
có một phương pháp trừu tượng: foreach
. Khi bạn gọi foreach
, bộ sưu tập sẽ cung cấp cho hàm đã truyền tất cả các phần tử mà nó giữ, cái này đến phần tử khác.
Mặt khác, một Iterable
phương thức có as trừu tượng iterator
, trả về một Iterator
. Bạn có thể gọi next
một Iterator
để nhận phần tử tiếp theo tại thời điểm bạn chọn. Cho đến khi bạn làm vậy, nó phải theo dõi vị trí của nó trong bộ sưu tập và những gì tiếp theo.
Iterable
mở rộng Traversable
, vì vậy tôi đoán bạn có nghĩa là Traversable
s mà không phải Iterable
là s.
Traversable
giao diện không yêu cầu giữ trạng thái, trong khi tuân thủ Iterator
giao diện thì có.
Traversable
s Iterable
không giữ bất kỳ trạng thái lặp lại nào. Nó Iterator
được tạo và trả lại bởi Iterable
cái giữ trạng thái.
Hãy coi đó là sự khác biệt giữa thổi và hút.
Khi bạn gọi một Traversable
s foreach
hoặc các phương thức dẫn xuất của nó, nó sẽ thổi các giá trị của nó vào hàm của bạn tại một thời điểm - vì vậy nó có quyền kiểm soát việc lặp lại.
Với giá trị Iterator
trả về bởi một Iterable
mặc dù, bạn hút các giá trị ra khỏi nó, tự mình kiểm soát thời điểm chuyển sang giá trị tiếp theo.
tl; dr Iterables
là những Traversables
thứ có thể tạo ra trạng tháiIterators
Đầu tiên, hãy biết rằng đó Iterable
là trang con của Traversable
.
Thứ hai,
Traversable
yêu cầu triển khai foreach
phương thức, được sử dụng bởi mọi thứ khác.
Iterable
yêu cầu triển khai iterator
phương thức, được sử dụng bởi mọi thứ khác.
Ví dụ, việc find
áp Traversable
dụng cho các sử dụng foreach
(thông qua một để hiểu) và ném một BreakControl
ngoại lệ để dừng lặp lại khi đã tìm thấy phần tử thỏa mãn.
trait TravserableLike {
def find(p: A => Boolean): Option[A] = {
var result: Option[A] = None
breakable {
for (x <- this)
if (p(x)) { result = Some(x); break }
}
result
}
}
Ngược lại, hàm Iterable
trừ sẽ ghi đè triển khai này và gọi find
hàm Iterator
, chỉ đơn giản là dừng lặp lại khi phần tử được tìm thấy:
trait Iterable {
override /*TraversableLike*/ def find(p: A => Boolean): Option[A] =
iterator.find(p)
}
trait Iterator {
def find(p: A => Boolean): Option[A] = {
var res: Option[A] = None
while (res.isEmpty && hasNext) {
val e = next()
if (p(e)) res = Some(e)
}
res
}
}
Sẽ rất tốt nếu bạn không ném ra các ngoại lệ để Traversable
lặp lại, nhưng đó là cách duy nhất để lặp lại một phần khi chỉ sử dụng foreach
.
Từ một góc độ, Iterable
là đặc điểm đòi hỏi cao hơn / mạnh mẽ hơn, vì bạn có thể dễ dàng triển khai foreach
bằng cách sử dụng iterator
, nhưng bạn không thể thực sự triển khai iterator
bằng cách sử dụng foreach
.
Tóm lại, Iterable
cung cấp một cách để tạm dừng, tiếp tục hoặc ngừng lặp lại thông qua trạng thái Iterator
. Với Traversable
, tất cả hoặc không có gì (không có ngoại lệ cho điều khiển luồng).
Hầu hết thời gian điều đó không quan trọng và bạn sẽ muốn có giao diện chung hơn. Nhưng nếu bạn cần kiểm soát tùy chỉnh nhiều hơn đối với việc lặp lại, bạn sẽ cần một Iterator
, mà bạn có thể truy xuất từ một Iterable
.
Câu trả lời của Daniel nghe hay đấy. Hãy để tôi xem nếu tôi có thể diễn đạt nó theo cách của riêng tôi.
Vì vậy, một Iterable có thể cung cấp cho bạn một trình vòng lặp, cho phép bạn duyệt qua các phần tử một cách lần lượt (sử dụng next ()) và dừng lại và đi tùy ý. Để làm điều đó, trình lặp cần giữ một "con trỏ" nội bộ đến vị trí của phần tử. Nhưng một Traversable cung cấp cho bạn phương pháp, foreach, để duyệt qua tất cả các phần tử cùng một lúc mà không dừng lại.
Một cái gì đó như Phạm vi (1, 10) chỉ cần có 2 số nguyên ở trạng thái có thể chuyển ngang. Nhưng Phạm vi (1, 10) như một Lặp lại cung cấp cho bạn một trình vòng lặp cần sử dụng 3 số nguyên cho trạng thái, một trong số đó là chỉ mục.
Xem xét rằng Traversable cũng cung cấp foldLeft, foldRight, bước trước của nó cần phải duyệt các phần tử theo một thứ tự đã biết và cố định. Do đó, có thể triển khai một trình vòng lặp cho một Trình duyệt. Ví dụ: def iterator = toList.iterator
Traversable
trong Scala 2.13 (nó vẫn được giữ như một bí danh NỮA choIterable
đến 2.14)