Suche…


Syntax

  • Klasse Einige [+ T] (Wert: T) erweitert Option [T]

  • Objekt Keine erweitert Option [Nichts]

  • Option [T] (Wert: T)

    Konstruktor, um je nach angegebenem Some(value) entweder einen Some(value) oder None zu erstellen.

Optionen als Sammlungen

Option haben einige nützliche Funktionen höherer Ordnung, die leicht verstanden werden können, wenn Optionen als Sammlungen mit null oder einem Element None verhält sich None wie die leere Sammlung und Some(x) wie eine Sammlung mit einem einzelnen Element, x .

val option: Option[String] = ???

option.map(_.trim) // None if option is None, Some(s.trim) if Some(s)
option.foreach(println) // prints the string if it exists, does nothing otherwise
option.forall(_.length > 4) // true if None or if Some(s) and s.length > 4
option.exists(_.length > 4) // true if Some(s) and s.length > 4
option.toList // returns an actual list

Option anstelle von Null verwenden

In Java (und anderen Sprachen) ist die Verwendung von null eine häufige Methode, um anzuzeigen, dass an eine Referenzvariable kein Wert angehängt ist. In Scala wird die Verwendung von Option Verwendung von null vorgezogen. Option umschließt Werte, die möglicherweise null .

None ist eine Unterklasse von Option die eine Nullreferenz einschließt. Some sind eine Unterklasse von Option die eine nicht-null-Referenz einschließt.

Eine Referenz einwickeln ist einfach:

val nothing = Option(null) // None
val something = Option("Aren't options cool?") // Some("Aren't options cool?")

Dies ist ein typischer Code, wenn eine Java-Bibliothek aufgerufen wird, die möglicherweise eine Nullreferenz zurückgibt:

val resource = Option(JavaLib.getResource())
// if null, then resource = None
// else resource = Some(resource)

Wenn getResource() einen null zurückgibt, ist die resource ein None Objekt. Andernfalls handelt es sich um ein Some(resource) Objekt Some(resource) . Die bevorzugte Methode zum Umgang mit einer Option ist die Verwendung von Funktionen höherer Ordnung innerhalb des Option . Wenn Sie beispielsweise prüfen möchten, ob Ihr Wert nicht None (ähnlich wie beim Überprüfen, ob value == null ), würden Sie die isDefined Funktion verwenden:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isDefined) {  // resource is `Some(_)` type
  val r: Resource = resource.get
  r.connect()
}

Um nach einer null suchen, können Sie Folgendes tun:

val resource: Option[Resource] = Option(JavaLib.getResource())
if (resource.isEmpty) { // resource is `None` type.
  System.out.println("Resource is empty! Cannot connect.")
}

Es wird bevorzugt, dass Sie die bedingte Ausführung des umschlossenen Werts einer Option (ohne die Option.get Methode "außergewöhnlich" Option.get verwenden), indem Sie die Option als Monade behandeln und foreach :

val resource: Option[Resource] = Option(JavaLib.getResource())
resource foreach (r => r.connect())
// if r is defined, then r.connect() is run
// if r is empty, then it does nothing

Wenn eine Resource erforderlich ist (im Gegensatz zu einer Option[Resource] -Instanz), können Sie Option zum Schutz vor NULL-Werten verwenden. Hier liefert die getOrElse Methode einen Standardwert:

lazy val defaultResource = new Resource()
val resource: Resource = Option(JavaLib.getResource()).getOrElse(defaultResource)

Java-Code kann Scalas Option nicht ohne weiteres verarbeiten. Wenn Sie Werte an Java-Code übergeben, ist es eine gute Form, eine Option zu entpacken, wobei null oder ein sinnvoller Standardwert übergeben wird:

val resource: Option[Resource] = ???
JavaLib.sendResource(resource.orNull)
JavaLib.sendResource(resource.getOrElse(defaultResource)) // 

Grundlagen

Eine Option ist eine Datenstruktur, die entweder einen einzelnen oder keinen Wert enthält. Eine Option kann als Sammlung von null oder einem Element betrachtet werden.

Option ist eine abstrakte Klasse mit zwei Kindern: Some und None .

Some enthält einen einzelnen Wert und " None enthält keinen Wert.

Option ist in Ausdrücken nützlich, die andernfalls null , um das Fehlen eines konkreten Werts darzustellen. Dies schützt vor einer NullPointerException und ermöglicht die Zusammensetzung vieler Ausdrücke, die möglicherweise keinen Wert mit Kombinatoren wie Map , FlatMap usw. zurückgeben.

Beispiel mit Map

val countries = Map(
  "USA" -> "Washington",
  "UK" -> "London",
  "Germany" -> "Berlin",
  "Netherlands" -> "Amsterdam",
  "Japan" -> "Tokyo"
)
    
println(countries.get("USA")) // Some(Washington)
println(countries.get("France")) // None
println(countries.get("USA").get) // Washington
println(countries.get("France").get) // Error: NoSuchElementException
println(countries.get("USA").getOrElse("Nope")) // Washington
println(countries.get("France").getOrElse("Nope")) // Nope

Option[A] ist versiegelt und kann daher nicht erweitert werden. Daher ist die Semantik stabil und verlässlich.

Optionen für Verständnis

Option haben eine flatMap Methode. Dies bedeutet, dass sie für ein Verständnis verwendet werden können. Auf diese Weise können wir reguläre Funktionen zur Bearbeitung von Option ohne sie neu definieren zu müssen.

val firstOption: Option[Int] = Option(1)
val secondOption: Option[Int] = Option(2)

val myResult = for {
  firstValue <- firstOption
  secondValue <- secondOption
} yield firstValue + secondValue
// myResult: Option[Int] = Some(3)

Wenn einer der Werte " None ist, lautet das Endergebnis der Berechnung " None .

val firstOption: Option[Int] = Option(1)
val secondOption: Option[Int] = None

val myResult = for {
  firstValue <- firstOption
  secondValue <- secondOption
} yield firstValue + secondValue
// myResult: Option[Int] = None

Hinweis: Dieses Muster erstreckt sich allgemeiner auf Konzepte, die Monad . (Weitere Informationen sollten auf Seiten verfügbar sein, die sich auf Verständnis und Monad 's beziehen.)

Im Allgemeinen ist es nicht möglich, verschiedene Monaden zum Verständnis zu mischen. Da Option jedoch leicht in eine Iterable konvertiert werden kann, können Sie Option und Iterable s einfach mischen, indem Sie die .toIterable Methode aufrufen.

val option: Option[Int] = Option(1)
val iterable: Iterable[Int] = Iterable(2, 3, 4, 5)

// does NOT compile since we cannot mix Monads in a for comprehension
// val myResult = for {
//   optionValue <- option
//   iterableValue <- iterable
//} yield optionValue + iterableValue

// It does compile when adding a .toIterable on the option
val myResult = for {
  optionValue <- option.toIterable
  iterableValue <- iterable
} yield optionValue + iterableValue
// myResult: Iterable[Int] = List(2, 3, 4, 5)

Eine kleine Anmerkung: Wenn wir unser Verständnis für das Verständnis definiert hätten, würde sich das Gegenteil um das Verständnis herum ausrechnen, da unsere Option implizit konvertiert würde. Aus diesem Grund ist es sinnvoll, diese .toIterable Funktion (oder die entsprechende Funktion, abhängig von der verwendeten Sammlung) immer aus .toIterable hinzuzufügen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow