Il y a d'autres questions comme la Scala: Quelle est la différence entre Traversable et Itératif traits Scala collections? et Comment aurais-je obtenir la somme des carrés des deux Listes en Scala? qui répond à la question partiellement. J'ai senti une question qui couvre le tout à un seul endroit du sens.
Réponses
Trop de publicités?Traversable est le top des collections de la hiérarchie. Sa principale méthode consiste 'foreach' donc ça permet de faire quelque chose pour chaque élément de la collection.
Un objet iterable pouvez créer un Itérateur sur la base de laquelle foreach peut être mis en œuvre. Ceci définit l'ordre des éléments, bien que cet ordre peut changer pour chaque Itérateur.
Seq(uence) est un objet iterable où l'ordre des éléments est fixe. À cet effet, il est logique de parler à propos de l'index d'un élément.
Les ruisseaux sont paresseux Séquences. I. e. les éléments d'un cours d'eau ne peuvent pas être calculés avant qu'ils sont accessibles. De ce fait, il est possible de travailler avec un nombre infini de séquences comme la séquence de tous les nombres entiers.
Les vues sont des versions non strictes de collections. Des méthodes comme le filtre et la carte en vue seulement d'exécuter le passé de fonctions de chaque élément est disponible. Ainsi, une carte sur une énorme collection renvoie immédiatement car il crée juste un wrapper autour de la collection d'origine. Seulement lorsque l'on a accès à un élément, la cartographie devient réellement exécutée (l'élément). Notez que la Vue n'est pas une classe, mais il y a beaucoup de XxxView des classes pour les diverses collections.
Un commentaire je tiens à ajouter sur les flux vs itérateurs. Les deux ruisseaux et les itérateurs peuvent être utilisés pour mettre en œuvre longue, non-stricte, potentiellement infinie des collections qui ne sont pas de calculer une valeur jusqu'à ce qu'il est nécessaire.
Cependant, il y a un problème épineux par "l'exécution" qui se pose lors de cette opération, qui peut être évité par l'utilisation des itérateurs, mais pas les flux, et dans le processus, souligne une importante différence sémantique entre les deux. C'est peut-être illustré plus clairement comme suit:
def runiter(start: Int) {
// Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
Ce code crée un courant infini qui commence à une valeur donnée et retours successifs entiers. Il est utilisé comme un stand-in pour un code plus complexe qui peut être, par exemple, d'ouvrir une connexion à internet et les valeurs de retour de la connexion en tant que de besoin.
Résultat:
scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
Noter soigneusement comment l'exécution nécessaires au calcul de la première valeur se produit AVANT l'endroit où le flux de valeurs sont effectivement utilisés. Si cette première exécution implique, par exemple, l'ouverture d'un fichier ou d'une connexion internet et il y a un long délai d'attente après la création du flux et avant tout les valeurs sont utilisées, cela peut être très problématique -- vous allez vous retrouver avec un descripteur de fichier ouvert la séance autour de, et pire encore, votre connexion internet peut de temps, provoquant l'ensemble de la chose à l'échec.
Une simple tentative de le fixer à l'aide d'un vide initial stream ne fonctionne pas:
def runiter(start: Int) {
// Create a stream that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1)
Stream[Int]() ++ loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
Résultat (comme avant):
scala> runiter(3)
(I computed a value,3)
about to loop
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
Cependant, vous pouvez résoudre ce problème en changeant le flux vers un itérateur avec un vide initial itérateur, même si c'est loin d'être évident que c'est le cas:
def runiter(start: Int) {
// Create an iterator that returns successive integers on demand, e.g. 3, 4, 5, ....
val iter = {
def loop(v: Int): Iterator[Int] = { println("I computed a value", v); Iterator(v)} ++ loop(v+1)
Iterator[Int]() ++ loop(start)
}
// Now, sometime later, we retrieve the values ....
println("about to loop")
for (x <- iter) {
if (x < 10) println("saw value", x) else return
}
}
Résultat:
scala> runiter(3)
about to loop
(I computed a value,3)
(saw value,3)
(I computed a value,4)
(saw value,4)
(I computed a value,5)
(saw value,5)
(I computed a value,6)
(saw value,6)
(I computed a value,7)
(saw value,7)
(I computed a value,8)
(saw value,8)
(I computed a value,9)
(saw value,9)
(I computed a value,10)
Notez que si vous n'ajoutez pas de vide initial itérateur, vous allez courir dans la même prématuré de l'exécution de problème avec les flux.