Comment puis-je faire 'if..else' dans une for-comprehension?
Je pose une question très simple qui m'ont troublé récemment.
Je veux écrire un Scala Pour expression pour faire quelque chose comme ce qui suit:
for (i <- expr1) {
if (i.method) {
for (j <- i) {
if (j.method) {
doSomething()
} else {
doSomethingElseA()
}
}
} else {
doSomethingElseB()
}
}
Le problème est que, dans les multiples générateurs Pour l'expression, je ne sais pas où je peux mettre chacun à l'expression du corps.
for {i <- expr1
if(i.method) //where can I write the else logic ?
j <- i
if (j.method)
} doSomething()
Comment puis-je repasser le code de la Scala de Style?
source d'informationauteur Sawyer
Vous devez vous connecter pour publier un commentaire.
Le premier code que vous avez écrit est parfaitement valide, donc il n'y a pas besoin de le réécrire. D'ailleurs, vous avez dit que vous vouliez savoir comment le faire Scala de style. Il n'est pas vraiment un "Scala" de style, mais je vais assumer une plus fonctionnelles de style et de tactique.
La première préoccupation, c'est que ce ne retourne aucune valeur. Il n'est des effets secondaires, qui doivent être évités ainsi. Donc, la première modification serait comme ceci:
Maintenant, il y a une grande différence entre
et
Leur retour des choses différentes, et il ya des moments que vous voulez le plus tard, pas l'ancien. Je vais supposer que vous voulez que l'ancienne, bien que. Maintenant, avant de poursuivre, nous allons corriger le code. Il est laid, difficile à suivre et peu utile. Nous allons à refactoriser par l'extraction de méthodes.
C'est déjà beaucoup plus propre, mais il n'est pas de retour du tout ce à quoi nous nous attendons. Regardons la différence:
Le type de
result
il estArray[AnyRef]
tandis que l'utilisation de plusieurs générateurs de rendementArray[Element]
. La partie la plus facile de le résoudre est: est-ceMais cela ne fonctionne pas, parce que classifyElements lui-même renvoie
AnyRef
et nous voulons le retour d'une collection. Maintenant,validElements
retour d'une collection, de sorte que n'est pas un problème. Nous avons seulement besoin de fixer leelse
partie. DepuisvalidElements
est au retour d'uneIndexedSeq
revenons que sur leelse
partie. Le résultat final est:Qui fait exactement la même combinaison de boucles et de conditions que vous avez présenté, mais il est beaucoup plus lisible et facile à changer.
Sur Le Rendement
Je pense qu'il est important de noter une chose au sujet du problème présenté. Simplifions:
Maintenant, qui est mis en œuvre avec
foreach
(voir iciou d'autres questions et d'y répondre). Cela signifie que le code ci-dessus fait exactement la même chose que ce code:Exactement la même chose. Ce n'est pas vrai du tout quand on est à l'aide de
yield
. Les expressions suivantes ne donnent pas le même résultat:Le premier extrait sera mis en œuvre par le biais de deux
map
appels, tandis que la deuxième extrait de l'utilisation d'unflatMap
et unmap
.C'est seulement dans le contexte de
yield
qu'elle même n'a aucun sens de s'inquiéter sur l'imbrication desfor
boucles ou à l'aide de plusieurs générateurs. Et, en fait, générateurs représente le fait que quelque chose est en train généréqui est seulement vrai de vrai pour-interprétations (ceuxyield
chose).La partie
peut être réécrit comme
(bien sûr, vous pouvez utiliser un taux de rendement au lieu de cela, si votre faire.. méthodes de retourner quelque chose)
Ici, il n'est pas si terrible utile, mais si vous avez plus profondément la structure imbriquée, il pourrait...
Vous ne pouvez pas. L'(expr; si) construire juste de filtrer l'élément qui doit être traité dans la boucle.
Si l'ordre n'est pas important pour les appels à doSomething() et doSomethingElse (), alors vous pouvez réorganiser le code comme ceci.
Pour répondre à votre question initiale, je pense que pour les interprétations peuvent être très agréable pour des cas d'utilisation spécifiques, et votre exemple ne tient pas bien.
Les conditions spécifiées dans un Scala pour l'opération de la loi de filtrer les éléments de générateurs. Les éléments qui ne remplit pas les conditions sont ignorés et ne sont pas présentés pour le rendement /bloc de code.
Ce que cela signifie est que si vous voulez effectuer suppléant opérations basée sur une expression conditionnelle, le test doit être différées au rendement /bloc de code.
Aussi être conscient que l'opération est relativement onéreux (pour l'instant) donc peut-être une simple approche itérative, peut-être plus approprié, peut-être quelque chose comme:
Mise à jour:
Si vous devez en utiliser un pour la compréhension et vous pouvez vivre avec certaines restrictions, cela peut fonctionner: