Cas d'utilisation pour les cours d'eau en Scala
En Scala il y a une classe de Flux est très semblable à un itérateur. Le sujet Différence entre Itérateur et Flux en Scala? offre quelques perspectives sur les similitudes et les différences entre les deux.
Voir comment utiliser un flux de données est assez simple, mais je n'ai pas très nombreux commune cas d'utilisation où je voudrais utiliser un flux plutôt que d'autres artefacts.
Les idées que j'ai en ce moment:
- Si vous avez besoin de faire usage d'une série infinie. Mais cela ne semble pas comme sur un cas d'utilisation pour moi, donc ça ne correspond pas à mes critères. (Merci de me corriger si il est courant et je n'ai qu'une tache aveugle)
- Si vous avez une série de données, où chaque élément doit être calculée, mais que vous souhaitez réutiliser plusieurs fois. C'est faible, parce que je pouvais juste de le charger dans une liste qui est conceptuellement plus facile à suivre pour un grand sous-ensemble de la population des développeurs.
- Peut-être il ya un grand ensemble de données ou d'un calcul coûteux de la série et il y a une forte probabilité que les éléments dont vous avez besoin ne nécessitera pas de visiter tous les éléments. Mais dans ce cas, un Itérateur serait un bon match sauf si vous avez besoin de faire plusieurs recherches, dans ce cas, vous pourriez utiliser une liste même si elle serait un peu moins efficace.
- Il y a une série complexe de données qui doivent être réutilisés. De nouveau, une liste pourrait être utilisé ici. Bien que dans ce cas les deux cas, serait également difficile à utiliser et d'un Flux serait plus adapté car pas tous les éléments doivent être chargés. Mais encore une fois pas commun... ou est-il?
Donc ai-je raté une grosse utilise? Ou est-ce un développeur de préférence, pour la plupart,?
Grâce
Vous devez vous connecter pour publier un commentaire.
La principale différence entre un
Stream
et unIterator
est que ce dernier est mutable et "one-shot", pour ainsi dire, alors que le premier ne l'est pas.Iterator
a une meilleure mémoire queStream
, mais le fait qu'il est mutable peut être gênant.Prendre ce classique du premier générateur de nombres, par exemple:
Il peut facilement être écrit avec une
Iterator
ainsi, mais unIterator
ne garder les primes calculées jusqu'à présent.Donc, un aspect important d'un
Stream
est que vous pouvez passer à d'autres fonctions sans avoir dupliqué le premier, ou d'avoir à générer de nouveau et de nouveau.Comme coûteux calculs/infini listes, ces choses peuvent être faites avec
Iterator
ainsi. Infini listes sont en fait très utiles -- vous ne savez pas parce que vous ne l'avez pas, si vous avez vu les algorithmes qui sont plus complexes que ce qui est strictement nécessaire pour traiter forcée finis tailles.Stream
n'est jamais paresseux dans son élément de tête. La tête d'unStream
est stocké dans évalué forme. Si l'on a besoin d'une séquence où aucun élément (y compris la tête) est calculée jusqu'à ce que demandé, puisIterator
est le seul choix."a"#::"b"#::"c"#::"d"#::Stream.empy[String].drop(3)
permettra d'évaluer "a", "b", "c" et "d" . "d", car il devient la tête.En plus de Daniel réponse, gardez à l'esprit que
Stream
est utile pour de court-circuit des évaluations. Par exemple, supposons que j'ai un énorme ensemble de fonctions qui prennent desString
et retourOption[String]
, et je veux garder leur exécution jusqu'à ce que l'un d'entre eux fonctionne:Bien, je ne veux certainement pas à exécuter le ensemble liste, et il n'est pas une méthode pratique sur
List
qui dit, "traitez-les comme des fonctions et de les exécuter jusqu'à ce que l'un d'entre eux renvoie autre chose queNone
". Que faire? Peut-être ceci:Cela prend une liste et le traite comme un
Stream
(qui n'a pas réellement d'évaluer quoi que ce soit), puis définit un nouveauStream
qui est un résultat de l'application de fonctions (mais cela ne veut pas évaluer rien encore), puis recherche le premier qui est définie--et là, comme par magie, il regarde en arrière et se rend compte qu'il doit appliquer la carte et obtenir les bonnes données à partir de la liste d'origine--et puis déballe deOption[Option[String]]
àOption[String]
à l'aide degetOrElse
.Voici un exemple:
Mais ça fonctionne? Si nous avons mis un
println
dans nos fonctions, nous pouvons donc dire que si on les appelle, nous obtenons(C'est avec Scala 2.8; 2.7 mise en œuvre du parfois de dépassement par un, malheureusement. Et notez que vous ne accumuler une longue liste de
None
comme vos échecs accumuler, mais sans doute cela est peu coûteux par rapport à votre vrai calcul ici.)Iterator
, j'ai donc décidé qu'il était à côté de la question.Que j'ai pu imaginer, que si vous votez quelques périphérique en temps réel, un Flux est plus pratique.
Penser à un traqueur de GPS, qui renvoie à la position réelle si vous le demandez. Vous ne pouvez pas précalculer l'endroit où vous serez en 5 minutes. Vous pouvez l'utiliser pour quelques minutes seulement de réaliser un chemin d'accès dans OpenStreetMap ou vous pouvez l'utiliser pour une expédition de plus de six mois dans un désert ou la forêt tropicale.
Ou d'un thermomètre numérique ou d'autres types de capteurs qui, à plusieurs reprises le retour de nouvelles données, dès lors que le matériel est vivant et tourné sur un fichier journal filtre pourrait être un autre exemple.
Stream
est àIterator
commeimmutable.List
est àmutable.List
. En favorisant l'immuabilité empêche une classe de bugs, parfois au détriment des performances.scalac elle-même n'est pas à l'abri de ces problèmes: http://article.gmane.org/gmane.comp.lang.scala.internals/2831
Comme Daniel souligne, en favorisant la paresse plus de rigueur peut simplifier les algorithmes et le rendre plus facile pour les composer.