if (Option.nonEmpty) vs Option.foreach

9

Ich möchte etwas Logik ausführen, wenn der Wert einer Option festgelegt ist.

Ich kam aus einem Java-Hintergrund:

%Vor%

Wenn ich ein bisschen weiter in scala gehe, kann ich das schreiben als:

%Vor%

Welcher ist besser? Die "foreach" klingt mehr "idiomatisch" und weniger Java, aber es ist weniger lesbar - "foreach", das auf einen einzelnen Wert angewendet wird, klingt seltsam.

    
Bozho 10.08.2013, 16:14
quelle

4 Antworten

17

Ihr Beispiel ist nicht vollständig und Sie verwenden keine minimale Syntax. Vergleichen Sie einfach diese zwei Versionen:

%Vor%

und

%Vor%

In beiden Versionen gibt es mehr syntaktischen Overhead in der if -Lösung, aber ich stimme zu, dass foreach auf einem Option verwirrend sein kann, wenn Sie es nur als optionalen Wert betrachten.

Stattdessen beschreibt foreach , dass Sie irgendeine Art von Nebenwirkungen machen wollen, was sehr sinnvoll ist, wenn Sie denken, dass Option eine Monade ist und foreach nur eine Methode, um sie zu transformieren. Die Verwendung von foreach hat außerdem den großen Vorteil, dass es das Refactoring einfacher macht - Sie können einfach seinen Typ in List oder eine andere Monade ändern und Sie erhalten keine Compilerfehler (wegen der großen Collections-Bibliothek von Scalas, auf die Sie nicht angewiesen sind Verwenden Sie nur Operationen, die auf Monaden funktionieren, es gibt viele Methoden, die für viele Typen definiert sind.)

    
sschaef 10.08.2013, 16:32
quelle
10

foreach macht Sinn, wenn Sie sich Option als List vorstellen, aber mit maximal einem Element.

Ein besserer Stil, IMO, ist ein Verständnis dafür:

%Vor%     
Ben James 10.08.2013 16:25
quelle
6

foreach ist sinnvoll, wenn Sie Option als eine Liste betrachten, die höchstens einen einzelnen Wert enthalten kann. Dies führt auch zu einer korrekten Intuition über viele andere Methoden, die für Option verfügbar sind.

Ich kann mir mindestens einen wichtigen Grund vorstellen, warum Sie foreach in diesem Fall bevorzugen sollten: Es beseitigt mögliche Laufzeitfehler. Mit dem nonEmpty -Ansatz müssen Sie an einem Punkt ein get * machen, was Ihr Programm spektakulär zum Absturz bringen kann, wenn Sie versehentlich vergessen, einmal nach Leerheit zu suchen.

Wenn du get komplett aus deinem Verstand löschst, um Fehler dieser Art zu vermeiden, ist ein Nebeneffekt, dass du weniger Nutzen für nonEmpty hast! Und Sie werden anfangen, foreach zu genießen und sich vom Compiler kümmern zu lassen, was geschehen soll, wenn Option leer ist.

Sie werden sehen, dass dieses Konzept an anderen Orten auftaucht. Du würdest es nie tun

%Vor%

Was Sie lieber sehen werden, ist

%Vor%

Das Prinzip ist, dass Sie vermeiden wollen, dass Sie Code schreiben müssen, der den Fehlerfall behandelt - Sie möchten diese Last auf den Compiler übertragen. Viele werden Ihnen sagen, dass Sie niemals get verwenden sollten, egal wie vorsichtig Sie denken, dass Sie vor der Überprüfung sind. Das macht die Dinge einfacher.

* Es sei denn, Sie möchten nur wissen, ob Option einen Wert enthält und nicht wirklich nach dem Wert interessiert. In diesem Fall ist nonEmpty in Ordnung. In diesem Fall dient es als eine Art toBoolean .

    
kqr 10.08.2013 16:31
quelle
2

Dinge, die ich in den anderen Antworten nicht gefunden habe:

  1. Wenn ich if verwende, bevorzuge ich if (opt isDefined) bis if (opt nonEmpty) , da ersteres weniger sammlungähnlich ist und es klarer macht, dass es sich um eine Option handelt, aber das kann Geschmackssache sein .

  2. if und foreach unterscheiden sich in dem Sinne, dass if ein Ausdruck ist, der einen Wert zurückgibt, während foreach Unit zurückgibt. In gewisser Weise ist die Verwendung von foreach sogar noch Java-ähnlicher als if , da Java eine foreach-Schleife hat und Java if kein Ausdruck ist. Verwenden Sie ein für das Verständnis ist mehr scala-like.

  3. Sie können auch Mustervergleiche verwenden (dies ist aber auch weniger idiomatisch)

  4. Sie können die Methode fold verwenden, die zwei Funktionen benötigt, damit Sie einen Ausdruck im Fall Some und einen anderen im Fall None auswerten können. Möglicherweise müssen Sie den erwarteten Typ explizit angeben, da die Art der Inferenz funktioniert (wie in hier ). Meiner Meinung nach kann es manchmal noch klarer sein, entweder Mustererkennung oder val result = if (opt isDefined) expression1 else expression2 zu verwenden.

Wenn Sie keinen Rückgabewert benötigen und wirklich nicht mit dem nicht definierten Fall umgehen müssen, können Sie foreach verwenden.

    
herman 11.12.2013 10:56
quelle

Tags und Links