Dans mon projet, nous migrons de Java vers Scala. J'ai une fonction en Java qui utilise continue
dans la boucle for et renvoie une valeur basée sur une condition if dans la boucle for comme ci-dessous.
type mismatch; Found : IndexedSeq[TSourceToken] Required: TSourceToken
Pour convertir cela en Scala, j'ai utilisé l'option Yield afin de filtrer les valeurs qui satisfont la condition else de l'expression if comme ci-dessous.
def getBeforeToken(token: TSourceToken): TSourceToken = { val tokens = token.container val index = token.posinlist for { i <- index -1 to 0 by -1 currentToken = tokens.get(i) if(currentToken.toString.trim.length != 0) } yield currentToken }
Je ne suis pas en mesure de savoir comment renvoyer la valeur générée par la boucle for. Le message d'erreur est
private TSourceToken getBeforeToken(TSourceToken token) { TSourceTokenList tokens = token.container; int index = token.posinlist; for ( int i = index - 1; i >= 0; i-- ) { TSourceToken currentToken = tokens.get( i ); if ( currentToken.toString( ).trim( ).length( ) == 0 ) { continue; } else { return currentToken; } } return token; }
Je comprends que le yield
collecte toutes les valeurs de la boucle for et sa condition à l'intérieur et entraîne une collection: IndexedSeq
et donc le message d'erreur. Je ne suis pas capable de penser à une logique à former telle qu'elle a été écrite dans le code Java. Quelqu'un pourrait-il me dire comment puis-je encadrer le code dans Scala sans utiliser yield
et casser la boucle for une fois que la condition else
est satisfaite?
3 Réponses :
Il n'y a pas for-loops
habituelles comme en java dans scala. for-yield
n'est pas la même chose que for-loop
. C'est juste du sucre syntaxique pour les combinaisons de fonctions flatMap
, map
et withFilter
. Aussi, dans scala, il est préférable de ne pas utiliser de mot-clé de return
. Le langage basé sur des expressions qui a une valeur de retour et un mot de return
peut casser la logique et un autre développeur ne peut pas s'y attendre.
Dans votre cas, il sera préférable d'utiliser find
pour rechercher un élément spécifique dans une collection par prédicat:
def getBeforeToken(token: TSourceToken): TSourceToken = { val tokens = token.container val index = token.posinlist (index - 1 to 0 by -1) .find(i => tokens.get(i).toString.trim.length != 0) .fold(token)(i => tokens.get(i)) }
Donc, dans ce cas, find
simplement casser la boucle pour la première valeur, la condition est satisfaite? Ma compréhension est-elle correcte?
@Metadata oui, il trouvera le premier jeton satisfait ou utilisera la valeur par défaut passée à getOrElse
J'ai l'impression que cela pourrait être plus facile en l'inversant, quelque chose comme token.container.view.take(index).reverse.find(_.toString.trim.nonEmpty).getOrElse(token)
Vous pouvez en lire beaucoup sur le rendement Scala. Voici quelques bons articles:
Mais je pense que ce n'est pas la bonne façon d'aborder cela dans Scala. Scala est un langage de programmation fonctionnel, et vous pouvez utiliser ses capacités.
En supposant que TSourceToken
est une classe de cas ayant deux membres:
val tokens = TSourceToken(Seq("", " ", " \n ", "real token", "\t\t", " ", " \n\n ", "token to ignore"), 5) val token = tokens.container.take(tokens.posinlist).filter(_.trim.nonEmpty).last
Où vous voulez choisir le dernier token qui n'est pas vide parmi les derniers posinlist. Il existe de nombreuses façons d'y parvenir. Une des façons dont je pensais est:
case class TSourceToken(container: Seq[String], posinlist: Int)
token aura un real token
, comme vous vous y attendez. L'exécution de code peut être trouvée sur Scastie .
un pour la compréhension n'est pas le bon outil pour ce problème: c'est pour la cartographie, pas pour la recherche.
Pour une réécriture simple qui réécrit simplement votre code java sur scala, utilisez une boucle while:
def getBeforeToken(token: TSoruceToken): TSourceToken = token.container.reverseIterator.collectFirst { case t if t.toString.trim.length != 0 => t }.getOrElse(token)
si token.container
est une collection, vous l' token.container
probablement sans itération explicite:
def getBeforeToken(token: TSourceToken): TSourceToken = { val tokens = token.container var i = index - 1 while (i >= 0) { val currentToken = tokens.get(i) if (currentToken.toString.trim.length != 0) return currentToken i -= 1 } token }
Pendant le processus de migration, il peut être judicieux de s'en tenir au premier, pour que la traduction presque mécanique soit effectuée le plus rapidement possible, avant d'essayer d'améliorer la qualité du code scala.
oh ok .. Compris maintenant. Il s'agit d'un Iterator Java <TSourceToken>.
pourquoi ne pas le convertir également en type Scala?