Retour à Scala

Je suis un programmeur débutant et je suis tombé sur un comportement étrange.

def balanceMain(elem: List[Char]): Boolean = { if (elem.isEmpty) if (count == 0) true; else false; if (elem.head == '(') balanceMain(elem.tail, open, count + 1);.... 

En gros, je veux retourner true si elem.isEmpty et count == 0 . Sinon, je veux retourner faux.

Maintenant, au-dessus, j’ai lu qu’il n’y a pas besoin d’append une déclaration de retour dans Scala. J’ai donc omis de return ci-dessus. Mais ça ne retourne pas le booléen. Si j’ajoute une déclaration de return true comme return true . ça marche parfaitement Pourquoi est-ce le cas?

Aussi, pourquoi est-il considéré comme une mauvaise pratique d’avoir des déclarations de retour dans Scala

Ce n’est pas aussi simple que d’omettre simplement le mot-clé de return . Dans Scala, s’il n’y a pas de return la dernière expression est considérée comme la valeur de retour. Donc, si la dernière expression est ce que vous voulez retourner, vous pouvez omettre le mot-clé de return . Mais si ce que vous voulez retourner n’est pas la dernière expression, alors Scala ne saura pas que vous vouliez le retourner .

Un exemple:

 def f() = { if (something) "A" else "B" } 

Ici, la dernière expression de la fonction f est une expression if / else qui est évaluée à une chaîne. Comme il n’y a pas de return explicite marqué, Scala déduira que vous vouliez retourner le résultat de cette expression if / else: une chaîne.

Maintenant, si nous ajoutons quelque chose après l’expression if / else:

 def f() = { if (something) "A" else "B" if (somethingElse) 1 else 2 } 

La dernière expression est maintenant une expression if / else qui est évaluée à un Int. Le type de retour de f sera donc Int. Si nous voulions vraiment qu’il retourne la chaîne, alors nous avons des problèmes parce que Scala n’a aucune idée que c’est ce que nous voulions. Ainsi, nous devons le réparer soit en stockant Ssortingng dans une variable et en le renvoyant après la deuxième expression if / else, soit en modifiant l’ordre afin que la partie Ssortingng se produise en dernier.

Enfin, nous pouvons éviter le mot-clé return même avec une expression if-else nestede comme la vôtre:

 def f() = { if(somethingFirst) { if (something) // Last expression of `if` returns a Ssortingng "A" else "B" } else { if (somethingElse) 1 else 2 "C" // Last expression of `else` returns a Ssortingng } 

}

Ce sujet est en fait un peu plus compliqué, comme décrit dans les réponses à ce jour. Cet article de blog de Rob Norris l’ explique plus en détail et donne des exemples de l’utilisation de return en cas de rupture de code (ou du moins d’effets non évidents).

À ce stade, permettez-moi de citer l’essence du message. La déclaration la plus importante est juste au début. Imprimez ceci comme une affiche et mettez-le sur votre mur 🙂

Le mot-clé de return n’est pas «facultatif» ou «inféré»; cela change la signification de votre programme et vous ne devriez jamais l’utiliser.

Il donne un exemple, où il casse réellement quelque chose, lorsque vous intégrez une fonction

 // Inline add and addR def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add scala> sum(33, 42, 99) res2: Int = 174 // alright def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR scala> sumR(33, 42, 99) res3: Int = 33 // um. 

car

Une expression de return , lorsqu’elle est évaluée, abandonne le calcul en cours et renvoie à l’appelant la méthode dans laquelle le return apparaît.

Ceci est seulement l’un des exemples donnés dans la publication liée et c’est le plus facile à comprendre. Il y en a plus et je vous encourage fortement à y aller, à lire et à comprendre.

Lorsque vous venez de langages impératifs comme Java, cela peut sembler étrange au début, mais une fois que vous vous serez habitué à ce style, cela aura du sens. Laissez-moi terminer avec une autre citation:

Si vous vous trouvez dans une situation où vous pensez vouloir revenir plus tôt, vous devez repenser la manière dont vous avez défini votre calcul.

Je ne programme pas Scala, mais j’utilise un autre langage avec des retours implicites (Ruby). Vous avez du code après votre bloc if (elem.isEmpty) – la dernière ligne de code est ce qui est retourné, ce qui explique pourquoi vous n’obtenez pas ce que vous attendez.

EDIT: Voici un moyen plus simple d’écrire votre fonction. Il suffit d’utiliser la valeur booléenne de isEmpty et de compter pour retourner true ou false automatiquement:

 def balanceMain(elem: List[Char]): Boolean = { elem.isEmpty && count == 0 } 

Par défaut, la dernière expression d’une fonction sera renvoyée. Dans votre exemple, il y a une autre expression après le point, où vous voulez que votre valeur de retour. Si vous voulez retourner quelque chose avant votre dernière expression, vous devez toujours utiliser return .

Vous pouvez modifier votre exemple comme ceci, pour renvoyer un Boolean de la première partie

 def balanceMain(elem: List[Char]): Boolean = { if (elem.isEmpty) { // == is a Boolean resulting function as well, so your can write it this way count == 0 } else { // keep the rest in this block, the last value will be returned as well if (elem.head == "(") { balanceMain(elem.tail, open, count + 1) } // some more statements ... // just don't forget your Boolean in the end someBoolExpression } } 

N’écrivez pas les instructions if sans else correspondant. Une fois que vous ajoutez le else à votre fragment, vous verrez que vos true et false sont en fait les dernières expressions de la fonction.

 def balanceMain(elem: List[Char]): Boolean = { if (elem.isEmpty) if (count == 0) true else false else if (elem.head == '(') balanceMain(elem.tail, open, count + 1) else....