Ich bin ein Neuling Scala-Programmierer und stieß auf ein seltsames Verhalten.
def balanceMain(elem: List[Char]): Boolean =
{
if (elem.isEmpty)
if (count == 0)
true;
else false;
if (elem.head == '(')
balanceMain(elem.tail, open, count + 1);....
Oben möchte ich grundsätzlich true zurückgeben, wenn elem.isEmpty
und count == 0
. Ansonsten möchte ich false zurückgeben.
Jetzt oben habe ich gelesen, dass es nicht notwendig ist, eine return-Anweisung in scala hinzuzufügen. Also habe ich return
oben weggelassen . Der boolesche Wert wird jedoch nicht zurückgegeben. Wenn ich eine return-Anweisung als hinzufüge return true
. es funktioniert perfekt. Wieso ist es so?
Warum wird es auch als schlechte Praxis angesehen, Rückgabeanweisungen in Scala zu haben?
Antworten:
Es ist nicht so einfach, nur das
return
Schlüsselwort wegzulassen . Wenn in Scala keine vorhanden ist,return
wird der letzte Ausdruck als Rückgabewert verwendet. Wenn Sie also den letzten Ausdruck zurückgeben möchten, können Sie dasreturn
Schlüsselwort weglassen . Wenn das, was Sie zurückgeben möchten, nicht der letzte Ausdruck ist, weiß Scala nicht, dass Sie ihn zurückgeben möchten .Ein Beispiel:
def f() = { if (something) "A" else "B" }
Hier ist der letzte Ausdruck der Funktion
f
ein if / else-Ausdruck, der zu einem String ausgewertet wird. Da keine explizitereturn
Markierung vorhanden ist, schließt Scala, dass Sie das Ergebnis dieses if / else-Ausdrucks zurückgeben möchten: einen String.Wenn wir nun nach dem if / else-Ausdruck etwas hinzufügen :
def f() = { if (something) "A" else "B" if (somethingElse) 1 else 2 }
Jetzt ist der letzte Ausdruck ein if / else-Ausdruck, der zu einem Int ausgewertet wird. Der Rückgabetyp von
f
wird also Int sein. Wenn wir wirklich wollten, dass der String zurückgegeben wird, sind wir in Schwierigkeiten, weil Scala keine Ahnung hat , dass wir das beabsichtigt haben. Daher müssen wir das Problem beheben, indem wir entweder den String in einer Variablen speichern und nach dem zweiten if / else-Ausdruck zurückgeben oder die Reihenfolge so ändern, dass der String-Teil zuletzt auftritt.Schließlich können wir das
return
Schlüsselwort auch mit einem verschachtelten if-else-Ausdruck wie Ihrem vermeiden :def f() = { if(somethingFirst) { if (something) // Last expression of `if` returns a String "A" else "B" } else { if (somethingElse) 1 else 2 "C" // Last expression of `else` returns a String }
}}
quelle
return "A"
undreturn "B"
?Dieses Thema ist tatsächlich etwas komplizierter, wie in den bisherigen Antworten beschrieben. Dieser Blogpost von Rob Norris erklärt es ausführlicher und gibt Beispiele dafür, wann die Verwendung von return Ihren Code tatsächlich beschädigt (oder zumindest nicht offensichtliche Auswirkungen hat).
Lassen Sie mich an dieser Stelle nur die Essenz des Beitrags zitieren. Die wichtigste Aussage ist gleich am Anfang. Drucken Sie dies als Poster aus und hängen Sie es an Ihre Wand :-)
Es gibt ein Beispiel, wo es tatsächlich etwas kaputt macht, wenn Sie eine Funktion inline
// 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.
weil
Dies ist nur eines der Beispiele im verlinkten Beitrag und am einfachsten zu verstehen. Es gibt noch mehr und ich ermutige Sie sehr, dorthin zu gehen, zu lesen und zu verstehen.
Wenn Sie aus imperativen Sprachen wie Java kommen, mag dies zunächst seltsam erscheinen, aber sobald Sie sich an diesen Stil gewöhnt haben, ist dies sinnvoll. Lassen Sie mich mit einem anderen Zitat schließen:
quelle
return
nur in Lambda-Ausdrücken verwenden, aber dies ist eine beschissene Design-Wahl in der Sprache, der Code sollte nicht einmal kompiliert werden (in Python wird dies vermieden, indem einlambda
Schlüsselwort ohne die return-Anweisung vorhanden ist). .. in jedem anderen Fall sehe ich kein wirkliches Problem bei der Verwendung,return
wenn Sie einen Wert zurückgeben möchten (und ja,Ich programmiere Scala nicht, aber ich verwende eine andere Sprache mit impliziten Rückgaben (Ruby). Sie haben Code nach Ihrem
if (elem.isEmpty)
Block - die letzte Codezeile ist die zurückgegebene, weshalb Sie nicht das bekommen, was Sie erwarten.BEARBEITEN: Hier ist eine einfachere Möglichkeit, Ihre Funktion zu schreiben. Verwenden Sie einfach den booleschen Wert von isEmpty und zählen Sie, um automatisch true oder false zurückzugeben:
def balanceMain(elem: List[Char]): Boolean = { elem.isEmpty && count == 0 }
quelle
explicit
Rückkehr wäre dann in diesem Fall angebracht.Schreiben Sie keine
if
Aussagen ohne entsprechendeelse
. Sobald Sie daselse
zu Ihrem Fragment hinzufügen , werden Sie sehen, dass Ihretrue
undfalse
tatsächlich die letzten Ausdrücke der Funktion sind.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....
quelle
Standardmäßig wird der letzte Ausdruck einer Funktion zurückgegeben. In Ihrem Beispiel gibt es einen weiteren Ausdruck nach dem Punkt, an dem Sie Ihren Rückgabewert möchten. Wenn Sie vor Ihrem letzten Ausdruck etwas zurückgeben möchten, müssen Sie noch verwenden
return
.Sie können Ihr Beispiel folgendermaßen ändern, um a
Boolean
aus dem ersten Teil zurückzugebendef 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 } }
quelle
Use-Case-Match für Zwecke der vorzeitigen Rücksendung. Sie werden gezwungen, alle Rückgabezweige explizit zu deklarieren, um den unachtsamen Fehler zu vermeiden, dass Sie vergessen, irgendwo eine Rückgabe zu schreiben.
quelle