55 Stimmen

for-Ausdrücke versus foreach in Scala

Ich arbeite mich durch die Programmierung in Scala und obwohl ich versucht bin, die Dinge aus der Perspektive von Python zu betrachten, möchte ich nicht "Python in Scala" programmieren.

Ich bin mir nicht ganz sicher, was ich in Bezug auf den Kontrollfluss tun soll: In Python verwenden wir for x in some_iterable zu Tode, und wir lieben es. Ein sehr ähnliches Konstrukt gibt es in Scala, das Odersky ein for nennt Ausdruck um sie wahrscheinlich von der Java for-Schleife zu unterscheiden. Außerdem hat Scala eine foreach Attribut (ich schätze, es wäre ein Attribut, ich weiß nicht genug über Scala, um es richtig zu benennen) für iterierbare Datentypen. Es scheint nicht so, als könnte ich foreach mehr zu tun, als eine Funktion für jedes Element im Container aufzurufen.

Dies wirft bei mir einige Fragen auf. Erstens, sind für Ausdrücke wichtig / häufig verwendete Konstrukte in Scala wie sie in Python sind, und zweitens, wann sollte ich verwenden foreach anstelle eines for-Ausdrucks (abgesehen vom offensichtlichen Fall des Aufrufs einer Funktion für jedes Element eines Containers)?

Ich hoffe, ich bin nicht furchtbar zweideutig oder zu weit gefasst, aber ich versuche gerade, einige der Design-/Sprachgrundlagen in Scala zu verstehen (was bisher sehr cool scheint).

60voto

huynhjl Punkte 41112

Python verwendet for in Listenauffassungen und Generatorausdrücken. Diese sind sehr ähnlich wie bei der Scala for Ausdruck:

Das ist Python

>>> letters = ['a', 'b', 'c', 'd']
>>> ints = [0, 1, 2, 3]
>>> [l + str(i) for l in letters for i in ints if i % 2 == 0]
['a0', 'a2', 'b0', 'b2', 'c0', 'c2', 'd0', 'd2']

Das ist Skala

scala> val letters = List('a', 'b', 'c', 'd')
scala> val ints = List(0, 1, 2, 3)
scala> for (l <- letters; i <- ints if i % 2 == 0) yield l.toString + i
res0: List[java.lang.String] = List(a0, a2, b0, b2, c0, c2, d0, d2)

Jedes Konstrukt kann eine Anzahl von Generatoren/Iteratoren aufnehmen, Filterausdrücke anwenden und einen kombinierten Ausdruck ergeben. In Python ist die (expr for v1 in gen1 if expr1 for v2 in gen2 if expr2) ist ungefähr gleichwertig mit:

for v1 in gen1:
  if expr1:
    for v2 in gen2:
      if expr2:
        yield expr

In Skala for (v1 <- gen1 if expr1; v2 <- gen2 if expr2) yield expr ist ungefähr gleichwertig mit:

gen1.withFilter(expr1).flatMap(v1 => gen2.withFilter(expr2).map(v2 => expr))

Wenn Sie die Python lieben for x in xs Syntax, werden Sie wahrscheinlich die Scala for Ausdruck.

Scala hat einige zusätzliche syntaktische und übersetzungsspezifische Besonderheiten. Syntaktisch gesehen for kann mit geschweiften Klammern verwendet werden, so dass Sie Anweisungen in separate Zeilen setzen können. Sie können auch Wertzuweisungen vornehmen.

val res = for {
    i <- 1 to 20; i2 = i*i
    j <- 1 to 20; j2 = j*j
    k <- 1 to 20; k2 = k*k
    if i2 + j2 == k2
  } yield (i, j, k)

Auch v1 <- gen1 führt wirklich ein Spiel durch case v1 => gen1 . Wenn es keine Übereinstimmung gibt, werden diese Elemente bei der Iteration ignoriert.

scala> val list = List(Some(1), None, Some(2))
scala> for (Some(i) <- list) yield i
res2: List[Int] = List(1, 2)

Ich denke for nimmt einen wichtigen Platz in der Sprache ein. Das kann ich daran erkennen, dass es in dem Buch, das Sie gerade lesen, ein ganzes Kapitel (23) darüber gibt!

28voto

Daniel C. Sobral Punkte 290004

Ja, Scala for comprehensions (wie sie allgemein bekannt sind) werden häufig verwendet, aber sie sind eigentlich nur syntaktischer Zucker für eine bestimmte Kombination von Methoden, und viele ziehen es vor, diese Methoden direkt aufzurufen, anstatt den syntaktischen Zucker zu verwenden.

Zum besseren Verständnis von Scala for comprehensions lesen Sie bitte diese Frage . Sie werden insbesondere feststellen, dass for (x <- xs) f(x) ist das Gleiche wie xs.foreach(x => f(x)) .

Nun, Sie erwähnen, dass Sie nicht viel Nutzen aus der foreach Methode, aber ich möchte darauf hinweisen, dass fast alle Methoden von Scala-Sammlungen mit nur einer Methode implementiert werden (können). foreach . Siehe die Dokumentation für Traversable -- alle seine Methoden können mit nur foreach .

Beachten Sie, dass Scalas yield hat keine Ähnlichkeit mit Pythons yield -- können Sie nachschlagen dass auch eine Frage.

3voto

Fabian Steeg Punkte 43903

Mit seiner Unterstützung für verschachtelte Iteration, Filter und Transformation würde ich sagen, dass Scalas for ist eine der Stärken der Sprache und sehr zentral. Ich neige dazu, sie der Verwendung von foreach , map y filter .

3voto

JOTN Punkte 6020

Das foreach ist ein funktionaler Stil, während das for ein imperativer Stil ist. Wenn Sie schon einmal mit Lisp oder Scheme gearbeitet haben, sind Sie bereits mit der funktionalen Programmierung vertraut. Wenn nicht, könnte es anfangs etwas verwirrend sein. Als Erstes würde ich mich mit der Closure-Syntax vertraut machen, also mit anonymen Funktionen, die Sie an Dinge wie foreach übergeben. Wenn Sie das erst einmal verstanden haben, ergibt alles mehr Sinn.

3voto

Northover Punkte 981

Ihre Fragen werden durch die folgenden Punkte weitgehend beantwortet:

Scalas For Comprehensions

Scala-Ausbeute

Um es zusammenzufassen: Das ist größtenteils eine Frage des Stils. Ich persönlich bevorzuge die funktionale Methodik, bevorzuge aber die Prägnanz von Comprehensions, wenn es um verschachtelte Schleifen geht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X