Nach den documentation:Was sind die Unterschiede zwischen Entweder und Option?
Eine gemeinsame Verwendung von entweder ist als Alternative zur Option für mit möglichen fehlenden Werten zu tun.
Warum würden Sie einen über den anderen verwenden?
Nach den documentation:Was sind die Unterschiede zwischen Entweder und Option?
Eine gemeinsame Verwendung von entweder ist als Alternative zur Option für mit möglichen fehlenden Werten zu tun.
Warum würden Sie einen über den anderen verwenden?
Die nette Sache über Either
ist, dass Sie den Grund verfolgen können, etwas fehlt. wenn Sie mit Options
Zum Beispiel arbeiten, könnten Sie in einer Situation wie diese sein:
val xOpt = Option(1)
val yOpt = Option(2)
val zOpt = None
val tupled = for {
x <- xOpt
y <- yOpt
z <- zOpt
} yield (x, y, z)
Nun, wenn tupled
None
ist, wissen wir nicht wirklich wissen, warum! Wenn dies für den Rest des Verhaltens ein wichtiges Detail ist, mit Either
helfen:
val tupled = for {
x <- xOpt.toRight("x is missing").right
y <- yOpt.toRight("y is missing").right
z <- zOpt.toRight("z is missing").right
} yield (x, y, z)
Dies kehrt entweder Left(msg)
, wo die Nachricht den ersten fehlenden Wert der entsprechenden Nachricht ist, oder Right(value)
für den fach vervielfachten Wert. Es ist üblich, Left
für Fehler und Right
für Erfolge zu verwenden.
Natürlich können Sie auch Either
breiter verwenden, nicht nur in Situationen mit fehlenden oder außergewöhnlichen Werten. Es gibt andere Situationen, in denen Either
helfen kann, die Semantik eines einfachen Union-Typs auszudrücken.
Das dritte gemeinsame Idiom für außergewöhnliche Werte zu verwenden, ist der Try
monadisch:
val xTry = Try("1".toInt)
val yTry = Try("2".toInt)
val zTry = Try("asdf".toInt)
val tupled = for {
x <- xTry
y <- yTry
z <- zTry
} yield (x, y, z)
Try[A]
isomorph zu Either[Throwable, A]
. Mit anderen Worten, Sie können eine Try
als Either
mit einem linken Typ von Throwable
behandeln, und Sie können jede Either
behandeln, die einen linken Typ von Throwable
als Try
hat. Auch Option[A]
ist homomorph zu Try[A]
. So können Sie eine Option
als Try
behandeln, die Fehler ignoriert. Daher kann man es auch transitiv als Either
bezeichnen. Tatsächlich unterstützt die Standard-Bibliothek einige dieser Transformationen:
//Either to Option
Left[Int, String](1).left.toOption //Some(1)
Right[Int, String]("foo").left.toOption //None
//Try to Option
Try("1".toInt).toOption //Some(1)
Try("foo".toInt).toOption //None
//Option to Either
Some(1).toRight("foo") //Right[String, Int](1)
(None: Option[Int]).toRight("foo") //Left[String, Int]("foo")
Die Standardbibliothek enthält nicht die Konvertierungen von Either
zu Try
, von Try
zu Either
oder Option
-Try
. Aber es ist ziemlich einfach Option
zu bereichern, Try
und Either
nach Bedarf:
object OptionTryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] = t.map(Right(_)).recover(PartialFunction(Left(_))).get
}
implicit class OptionToTry[T](val o: Option[T]) extends AnyVal {
def toTry(throwable: Throwable): Try[T] = o.map(Right(_)).getOrElse(Left(throwable))
}
}
Dies würde erlauben Sie zu tun:
import OptionTryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)
//Option to Try
Some(1).toTry(new Exception) //Success(1)
(None: Option[Int]).toTry(new Exception) //Failure(java.lang.Exception)
Either
kann als eine Verallgemeinerung von Option
angesehen werden. Wenn Sie den ersten Wert von Either
, beispielsweise beheben, indem es Unit
Einstellung, würden Sie etwas, das im Wesentlichen die gleiche Art und Weise verhält sich wie Option
:
Option[X] := Either[Unit, X]
In diesem Fall Left[Unit, X]
-None
entsprechen würde, und Right[Unit, X]
würde Some[X]
entsprechen.
Für Option[X]
, None
würde eine Art Fehlersignal einen Wert vom Typ X
, zu erhalten und Some[X]
würde Erfolg signalisieren. Für Either[Unit, X]
würde eine Instanz des Typs Left[Unit, X]
einen Fehler darstellen und Right[Unit, X]
würde den Erfolg darstellen.
Sie können jedoch die erste Komponente von Either
verwenden detaillierte Informationen über zu speichern warum etwas fehlgeschlagen ist, oder einige zusätzliche Informationen, die Sie von einem Fehler zu erholen hilft. Option
gibt Ihnen nur eine None
, die nicht sehr nützlich ist. Aber Either[F,X]
konnte entweder einen Erfolgswert Right[F, X]
, der im Wesentlichen nur ein Wrapper für X
ist, oder eine detaillierte Beschreibung des Fehlers in Left[F, X]
mit einem Wert des Typs F
, der den Fehler darstellt, zurückgeben.
Dadurch können Sie komplexere Wiederherstellungsstrategien definieren. Schauen Sie sich beispielsweise Form.scala
des Play! -Frameworks an. Sie verwenden Either
überall, weil sie entweder auf die Formularübermittlung des Benutzers reagieren oder ein teilweise ausgefülltes Formular zurücksenden möchten, das mit hilfreichen Fehlermeldungen versehen ist. Die Alternative dazu wäre, mit Option[TypeOfFormContent]
zu arbeiten, was zu None
auswerten würde, wenn einige der Formularfelder ungültige Eingabe enthielten. Dies würde wiederum bedeuten, dass der Benutzer etwas wie "Falsche Anfrage" erhält. Bitte füllen Sie das gesamte Formular erneut aus. " als Antwort, die absolut nervig wäre. Daher wird Either
anstelle von Option
verwendet, weil es tatsächlich verfolgen kann, was bei der Formularübermittlung genau falsch gelaufen ist.
Der Nachteil von Either
ist, dass es keine Monade ist: Um effektiv damit zu arbeiten, müssen Sie immer zwei verschiedene Rückrufe für die zwei verschiedenen Fälle passieren. Dies kann zu einer "Rückruf-Hölle" führen. Daher sollte man sorgfältig überlegen, ob eine genaue Beschreibung des Fehlers so wertvoll ist. Im Falle einer fehlgeschlagenen Formularübergabe ist eine detaillierte Beschreibung des Fehlers hilfreich, da der Benutzer nicht gezwungen werden soll, alles erneut einzugeben. In anderen Fällen kann Option
geeigneter sein, da die Programmierer nicht gezwungen werden, unnötige detaillierte Beschreibungen von nicht behebbaren Fehlern zu behandeln.
Andrey Tyukin ist zurückgekehrt! Ich muss allerdings zugeben - ich bin ein wenig enttäuscht, dass Sie für Ihre Antwort kein [weiteres fantastisches Diagramm] (http://stackoverflow.com/a/19739576/1427124) zusammengestellt haben. – DaoWen
@DaoWen: Ich denke, ich sollte definitiv etwas gegen mein "Internet-Alter-Ego" tun, denn momentan scheint es so, als wäre ein lächerliches Gif-Bild eines brennenden veganen Pandas die zweitwichtigste Idee, die ich je hatte. Ich werde in drei Monaten etwas unternehmen. –