it-swarm.com.de

Warum hat Scala hat Rückkehr, aber nicht Pause und fährt fort

Scala hat nicht break oder continue, daher erfordert ein gewisses Schleifenverhalten etwas mehr Nachdenken.

Beenden einer Schleife früh erfordert Schwanzrekursion, Ausnahmen oder scala.util.control.Breaks (verwendet Ausnahmen).

Der Grund dafür ist, dass es sich wie goto um Flusskonstrukte handelt, die den Fluss verdecken und auf bessere, weniger überraschende Weise erreicht werden können.

Es scheint jedoch, dass dieselben Argumente für return verwendet werden könnten.

Warum hat Scala absichtlich break und continue weggelassen, aber nicht return?

22
Paul Draper

Unterbrechen und fortfahren:

In ein Vortrag über Scala gab Martin Odersky drei Gründe an, die Pause nicht einzuschließen oder auf Folie 22 fortzufahren:

  • Sie sind ein bisschen zwingend erforderlich; Verwenden Sie besser viele kleinere Funktionen.
  • Fragen zur Interaktion mit Schließungen.
  • Sie werden nicht benötigt!

Und dann sagt er: "Wir können sie nur in den Bibliotheken unterstützen." Auf Folie 23 gibt er Code an, der break implementiert. Obwohl ich nicht genau weiß Scala gut genug, um sicher zu sein, sieht es so aus, als ob das kurze Snippet auf dieser Folie alles ist, was benötigt wird, um break und dieses continue könnte in ähnlich kurzem Code implementiert werden.

Die Möglichkeit, solche Dinge in Bibliotheken zu implementieren, vereinfacht die Kernsprache.

In 'Programming in Scala, Second Edition' von Martin Odersky, Lex Spoon und Bill Venners wird die folgende Erklärung gegeben:

Möglicherweise haben Sie bemerkt, dass break oder continue nicht erwähnt wurden. Scala lässt diese Befehle weg, weil sie nicht gut mit Funktionsliteralen zusammenpassen ... Es ist klar, was continue innerhalb einer while -Schleife bedeutet, aber was würde es bedeutet innerhalb eines Funktionsliteral? ... Es gibt viele Möglichkeiten, ohne break und continue zu programmieren, und wenn Sie Funktionsliterale nutzen, können diese Alternativen oft kürzer sein als der ursprüngliche Code .

Rückgabe:

Rückgaben können im Stil als etwas zwingend angesehen werden, da Rückgabe ein Verb ist, ein Befehl, etwas zu tun. Sie können aber auch rein funktional/deklarativ gesehen werden: Sie definieren den Rückgabewert der Funktion (auch wenn sie in einer Funktion mit mehreren Rückgaben jeweils nur eine Teildefinition geben).

Im selben Buch sagen sie Folgendes über return:

In Ermangelung einer expliziten return - Anweisung gibt eine Scala - Methode den zuletzt von der Methode berechneten Wert zurück. Der empfohlene Stil für Methoden besteht darin, explizite und insbesondere keine zu haben multiple, return Anweisungen. Stellen Sie sich stattdessen jede Methode als Ausdruck vor, der einen Wert ergibt, der zurückgegeben wird.

Methoden beenden und geben einen Wert zurück, auch wenn keine return -Anweisung verwendet wird. Daher kann es keine Probleme mit Schließungen geben, da Schließungen sonst nicht funktionieren würden.

Es kann auch kein Problem geben, sich gut mit Funktionsliteralen zu vermischen, da die Funktion sowieso einen Wert zurückgeben muss.

16
Michael Shaw

Ich denke, die vorherigen Antworten werden den Problemen gerecht, die Semantik für break oder continue auf sprachweite Weise für Scala mit relativ uneingeschränkten Kontexten zu definieren.

Ich habe eine kleine Bibliothek geschrieben, die break und continue in einem engeren Kontext definiert: Iteration über Sequenzen über Scala für Verständnis Wenn ich mich auf diesen Kontext konzentriere, glaube ich, dass die Semantik eindeutig und leicht zu begründen ist.

Die Bibliothek ist hier verfügbar: https://github.com/erikerlandson/breakable

Hier ist ein einfaches Beispiel dafür, wie es im Code aussieht:

scala> import com.manyangled.breakable._
import com.manyangled.breakable._

scala> val bkb2 = for {
     |   (x, xLab) <- Stream.from(0).breakable   // create breakable sequence with a method
     |   (y, yLab) <- breakable(Stream.from(0))  // create with a function
     |   if (x % 2 == 1) continue(xLab)          // continue to next in outer "x" loop
     |   if (y % 2 == 0) continue(yLab)          // continue to next in inner "y" loop
     |   if (x > 10) break(xLab)                 // break the outer "x" loop
     |   if (y > x) break(yLab)                  // break the inner "y" loop
     | } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = [email protected]

scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
0
eje