Eu olhei para esta questão, mas ainda não entendo a diferença entre traços Iteráveis e Traversáveis. Alguém pode explicar?
Eu olhei para esta questão, mas ainda não entendo a diferença entre traços Iteráveis e Traversáveis. Alguém pode explicar?
Respostas:
Para simplificar, os iteradores mantêm o estado, os percorríveis não.
Um Traversable
tem um método abstrato: foreach
. Quando você chama foreach
, a coleção alimenta a função passada com todos os elementos que ela mantém, um após o outro.
Por outro lado, an Iterable
tem como método abstrato iterator
, que retorna um Iterator
. Você pode chamar next
um Iterator
para obter o próximo elemento na hora de sua escolha. Até que você faça isso, ele precisa manter o controle de onde estava na coleção e do que vem a seguir.
Iterable
estende Traversable
, então eu acho que você quer dizer Traversable
s que não são Iterable
s.
Traversable
interface não exige manutenção do estado, ao passo que o cumprimento da interface exige Iterator
.
Traversable
s que são Iterable
não mantêm nenhum estado de iteração. É o Iterator
criado e devolvido pelo Iterable
que mantém o estado.
Pense nisso como a diferença entre soprar e sugar.
Quando você chama um Traversable
s foreach
, ou seus métodos derivados, ele vai soprar seus valores em sua função, um de cada vez - portanto, ele tem controle sobre a iteração.
Com o Iterator
retorno de um Iterable
pensamento, você suga os valores dele, controlando quando passar para o próximo.
tl; dr Iterables
são Traversables
que podem produzir statefulIterators
Primeiro, saiba que Iterable
é o subtítulo de Traversable
.
Segundo,
Traversable
requer a implementação do foreach
método, que é usado por todo o resto.
Iterable
requer a implementação do iterator
método, que é usado por todo o resto.
Por exemplo, a implementação de find
para Traversable
usa foreach
(por meio de um para compreensão) e lança uma BreakControl
exceção para interromper a iteração assim que um elemento satisfatório for encontrado.
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
}
}
Em contraste, a Iterable
subtração substitui essa implementação e chama find
o Iterator
, que simplesmente para de iterar assim que o elemento é encontrado:
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
}
}
Seria bom não lançar exceções para a Traversable
iteração, mas essa é a única maneira de iterar parcialmente ao usar apenas foreach
.
De uma perspectiva, Iterable
é o traço mais exigente / poderoso, já que você pode facilmente implementar foreach
using iterator
, mas não pode realmente implementar iterator
using foreach
.
Em resumo, Iterable
fornece uma maneira de pausar, retomar ou parar a iteração por meio de um stateful Iterator
. Com Traversable
, é tudo ou nada (sem exceções para controle de fluxo).
Na maioria das vezes, isso não importa e você desejará uma interface mais geral. Mas se você precisar de um controle mais personalizado sobre a iteração, precisará de um Iterator
, que pode ser recuperado de um Iterable
.
A resposta de Daniel parece boa. Deixe-me ver se consigo colocar em minhas próprias palavras.
Portanto, um Iterable pode fornecer um iterador, que permite percorrer os elementos um de cada vez (usando next ()) e parar e prosseguir quando quiser. Para fazer isso, o iterador precisa manter um "ponteiro" interno para a posição do elemento. Mas um Traversable fornece o método, foreach, para percorrer todos os elementos de uma vez sem parar.
Algo como Range (1, 10) precisa ter apenas 2 inteiros como estado de Traversable. Mas Range (1, 10) como um Iterable fornece um iterador que precisa usar 3 inteiros para o estado, um dos quais é um índice.
Considerando que Traversable também oferece foldLeft, foldRight, seu foreach precisa atravessar os elementos em uma ordem conhecida e fixa. Portanto, é possível implementar um iterador para um Traversable. Ex: def iterator = toList.iterator
Traversable
no Scala 2.13 (ainda é mantido como um apelido obsoletoIterable
até 2.14)