Was ist bei einer Option die idiomatische Methode, um ihren Wert zu ermitteln oder eine Ausnahme auszulösen?
def foo() : String = {
val x : Option[String] = ...
x.getOrException()
}
Was ist bei einer Option die idiomatische Methode, um ihren Wert zu ermitteln oder eine Ausnahme auszulösen?
def foo() : String = {
val x : Option[String] = ...
x.getOrException()
}
NoSuchElementException
auslösen. Außerdem kann diese Methode die meiste Zeit None sicher zurückgeben.
Antworten:
(BEARBEITEN: Dies ist nicht die beste oder idiomatischste Art, dies zu tun. Ich habe es geschrieben, als ich mit Scala nicht vertraut war. Ich lasse es hier als Beispiel dafür, wie man es nicht macht. Heutzutage würde ich es als @TravisBrown tun.)
Ich denke, es läuft wirklich auf zwei Dinge hinaus:
Wenn Sie zu diesem Zeitpunkt in Ihrem Code erwarten , dass der Wert vorhanden ist, und in dem Remote-Fall, dass Ihr Programm nicht schnell fehlschlagen soll , würde ich nur einen normalen Vorgang ausführen get
und Scala einen auslösen lassen, NoSuchElementException
wenn kein Wert vorhanden wäre ::
def foo (): String = { val x: Option [String] = ... x.get }}
Wenn Sie den Fall anders behandeln möchten (werfen Sie Ihre eigene Ausnahme), würde ein eleganterer Weg meiner Meinung nach so aussehen:
def foo (): String = { val x: Option [String] = Keine x Übereinstimmung { case Some (Wert) => Wert case None => neue MyRuntimeException auslösen ("blah") }} }}
Und natürlich, wenn Sie Ihren eigenen alternativen Wert für den Fall angeben möchten, dass der Option
ist , den None
Sie nur verwenden würden getOrElse
:
def foo (): String = { val x: Option [String] = Keine x.getOrElse ("mein alternativer Wert") }}
getOrElse
sollte bevorzugt werden, wenn das alles ist, was man tun möchte. Ich wollte nur den Fall von "falls definiert, auf X auswerten, wenn nicht, Ausnahme auslösen" veranschaulichen.
getOrElse
wie x.getOrElse(throw new MyRuntimeException("message"))
Eine throw
"Anweisung" ist wirklich ein Ausdruck in Scala und hat einen Typ Nothing
, der ein Subtyp jedes anderen Typs ist. Dies bedeutet, dass Sie einfach nur alt verwenden können getOrElse
:
def myGet[A](oa: Option[A]) = oa.getOrElse(throw new RuntimeException("Can't."))
Das solltest du aber wirklich, wirklich nicht tun.
OutOfMemoryError
. B. ).
Verwenden Sie einfach die .get-Methode.
def get[T](o:Option[T]) = o.get
Es wird eine NoSuchElementException ausgelöst, wenn o eine Instanz von None ist.
Grundsätzlich würde ich mit Optionen wie diesen arbeiten:
def addPrint(oi:Option[Int]) = oi.map(_+1).foreach(println)
addPrint(Some(41))
addPrint(Some(1336))
addPrint(None)
um Ihre spezifische Frage zu vermeiden.
get
ist dies eine schlechte Idee - es wird nur darüber berichtet, dass Sie etwas Unangenehmes tun. Das Verwenden getOrElse
und explizite Auslösen einer Ausnahme ist schwerer zu übersehen, wenn Sie entscheiden, dass dies nicht nur ein einmaliger Code ist und ihn sicherer machen möchte.
Ich hoffe, dies hilft Ihnen zu verstehen, wie Fehler (und allgemein Effekte) mithilfe von Typen dargestellt werden.
Verwenden Sie Option
diese Option, um optionale Werte zurückzugeben. Beispiel : Entität im Speicher kann nicht gefunden werden.
Verwenden Sie Option(possiblyNull)
diese Option , um Instanzen von zu vermeiden Some(null)
.
Verwenden Sie Either[Error, T]
diese Option , um den erwarteten Fehler zu melden. Beispiel : Das E-Mail-Format ist falsch, es kann keine Zeichenfolge auf eine Zahl analysiert werden usw.
Modellieren Sie Ihre Fehler als ADTs (einfach als Typhierarchien bezeichnet ), um sie beispielsweise links von den beiden zu verwenden, um komplexere Fehlerszenarien darzustellen.
Exception
Nur werfen , um unerwartete und nicht behebbare Fehler zu signalisieren. Wie fehlende Konfigurationsdatei.
Verwenden Sie Either.catchOnly
oder Try
oder Cats.IO
(erweitert) anstelle eines Catch-Blocks, um unerwartete Fehler zu behandeln. Hinweis: Sie können ADT weiterhin verwenden , diese jedoch von Wurfobjekten aus erweitern. Mehr über Either
vsTry
.
Verwenden Sie den Validated
Datentyp aus Cats lib, um Fehler zu akkumulieren, anstatt ausfallsicher zu sein ( Either
). Bevorzugen Sie jedoch entweder auf Modulebene, um die Zusammensetzung des Programms zu vereinfachen (um dieselben Typen zu haben). Zum Beispiel - Formulardatenvalidierung, Anhäufung von Analysefehlern.
Verwenden Sie die genannten Typen und optimieren Sie das Programm nicht präventiv - da Engpässe höchstwahrscheinlich in der Geschäftslogik und nicht in den Effekttypen enthalten sind.
Ein solcher Ansatz vereinfacht die Wartung und Aktualisierung Ihres Codes, da Sie darüber nachdenken können, ohne auf Implementierungsspezifikationen (auch bekannt als lokales Denken) einzugehen. Außerdem - Fehler reduzieren - können Sie einen Fehler im Typ nicht übersehen. Ausrichten und das Programm leichter (mit Hilfe von map
, flatMap
und anderen combinators) - da sie auf Typ - Ebene einfacher sind, und nicht mit nicht-lokalen Ausnahmen und Nebenwirkungen.
Weitere Informationen zum Erlernen der funktionalen Scala.
Beachten Sie jedoch, dass sich bei diesem Ansatz manchmal Typen stapeln und es schwieriger werden kann, Dinge zu komponieren. Gegeben zum Beispiel: x: Future[Either[Error, Option[T]]]
Was Sie tun können:
map
und flatMap
in Kombination mit dem Mustervergleich, um verschiedene Werte solcher Typen zu erstellen, zum Beispiel:x.faltMap { case Right(Some(v)) => anotherFuture(v); case Left(er) => ... }
Future[Option[T]]
Und schließlich ist in Ihrem Fall eine Option:
def foo() : Either[Error, String] = {
val x : Option[String] = ...
x match {
case Some(v) => Right(v)
case None => Left(Error(reason))
}
}
Scala unterstützt diesen Vorgang jetzt auf Karten mithilfe der getOrElse()
Methode (siehe Dokumentation hier)
Wie bereits erwähnt, ist das Auslösen einer Ausnahme in Scala ebenfalls ein Ausdruck.
Sie können also Folgendes tun:
myMap.getOrElse(myKey, throw new MyCustomException("Custom Message HERE")
.get
?