Przyjrzałem się temu pytaniu, ale nadal nie rozumiem różnicy między cechami iterowalnymi i przemiennymi. Czy ktoś może wyjaśnić?
Przyjrzałem się temu pytaniu, ale nadal nie rozumiem różnicy między cechami iterowalnymi i przemiennymi. Czy ktoś może wyjaśnić?
Odpowiedzi:
Mówiąc prościej, iteratory zachowują stan, a trawersable nie.
Traversable
Ma jeden abstrakcyjny sposób: foreach
. Kiedy wywołasz foreach
, kolekcja dostarczy przekazanej funkcji wszystkie elementy, które przechowuje, jeden po drugim.
Z drugiej strony Iterable
metoda ma as abstrakcyjną iterator
, która zwraca Iterator
. Możesz wezwać next
a, Iterator
aby uzyskać następny element w wybranym przez siebie momencie. Dopóki tego nie zrobisz, musi śledzić, gdzie był w kolekcji i co dalej.
Iterable
rozciąga się Traversable
, więc myślę, że masz na myśli, Traversable
że nie są Iterable
.
Traversable
interfejsem nie wymaga utrzymywania stanu, podczas gdy zgodność z Iterator
interfejsem wymaga.
Traversable
te, które są Iterable
, nie zachowują żadnego stanu iteracji. To Iterator
stworzone i zwrócone przez to, Iterable
co utrzymuje stan.
Potraktuj to jako różnicę między dmuchaniem a ssaniem.
Kiedy wywołasz a Traversable
s foreach
lub metody pochodne, będzie on wysyłał wartości do Twojej funkcji pojedynczo - dzięki czemu będzie miał kontrolę nad iteracją.
Z Iterator
powrotem przez Iterable
jednak wysysasz z niego wartości, kontrolując, kiedy samemu przejść do następnej.
tl; dr Iterables
są, Traversables
które mogą generować stanoweIterators
Po pierwsze, wiedz, że Iterable
to jest cecha Traversable
.
Druga,
Traversable
wymaga implementacji foreach
metody, która jest używana przez wszystko inne.
Iterable
wymaga implementacji iterator
metody, która jest używana przez wszystko inne.
Na przykład implementacja find
for Traversable
use foreach
(za pomocą a for compearing) i zgłasza BreakControl
wyjątek, aby zatrzymać iterację po znalezieniu zadowalającego elementu.
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
}
}
W przeciwieństwie do tego, Iterable
odejmowania nadpisuje to wdrożenie i rozmów find
w sprawie Iterator
, która po prostu przestaje iteracji po znalezieniu element:
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
}
}
Byłoby miło nie rzucać wyjątków dla Traversable
iteracji, ale to jedyny sposób na częściowe iterowanie, gdy używasz just foreach
.
Z jednej perspektywy Iterable
jest bardziej wymagającą / potężną cechą, ponieważ można ją łatwo wdrożyć foreach
za pomocą iterator
, ale tak naprawdę nie można zaimplementować iterator
za pomocą foreach
.
Podsumowując, Iterable
zapewnia sposób na wstrzymanie, wznowienie lub zatrzymanie iteracji za pomocą stanu Iterator
. Z Traversable
, to wszystko albo nic (bez wyjątków kontroli przepływu).
W większości przypadków nie ma to znaczenia, a będziesz chciał mieć bardziej ogólny interfejs. Ale jeśli kiedykolwiek będziesz potrzebować bardziej spersonalizowanej kontroli nad iteracją, będziesz potrzebować pliku Iterator
, który możesz pobrać z pliku Iterable
.
Odpowiedź Daniela brzmi dobrze. Zobaczmy, czy potrafię ująć to własnymi słowami.
Tak więc Iterable może dać ci iterator, który pozwala przechodzić elementy jeden po drugim (przy użyciu next ()) i zatrzymywać się i kontynuować, jak chcesz. Aby to zrobić, iterator musi utrzymywać wewnętrzny „wskaźnik” na pozycję elementu. Ale Traversable daje ci metodę, dla każdego, do przechodzenia przez wszystkie elementy naraz bez zatrzymywania się.
Coś w rodzaju Range (1, 10) musi mieć tylko 2 liczby całkowite jako stan jako Traversable. Ale Range (1, 10) jako Iterable daje iterator, który musi użyć 3 liczb całkowitych dla stanu, z których jedna jest indeksem.
Biorąc pod uwagę, że Traversable oferuje również foldLeft, foldRight, jego foreach musi przejść przez elementy w znanej i ustalonej kolejności. Dlatego można zaimplementować iterator dla Traversable. Np. Def iterator = toList.iterator
Traversable
w Scali 2.13 (jest nadal przechowywany jako przestarzały aliasIterable
do 2.14)