Zoeken…


Syntaxis

  • klasse Sommige [+ T] (waarde: T) breidt optie [T] uit

  • object Geen verlengt Optie [Niets]

  • Optie [T] (waarde: T)

    Constructor om een Some(value) of None te maken, afhankelijk van de opgegeven waarde.

Opties als collecties

Option hebben een aantal nuttige functies van hogere orde die gemakkelijk kunnen worden begrepen door opties te bekijken als collecties met nul of één items - waarbij None zich gedraagt als de lege collectie en Some(x) zich gedraagt als een collectie met een enkel item, 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

Optie gebruiken in plaats van Null

In Java (en andere talen) is het gebruik van null een veelgebruikte manier om aan te geven dat er geen waarde is gekoppeld aan een referentievariabele. In Scala heeft het gebruik van Option voorkeur boven het gebruik van null . Option verpakt waarden die mogelijk null .

None is een subklasse van Option een nulreferentie. Some is een subklasse van Option een niet-nulreferentie.

Een referentie wikkelen is eenvoudig:

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

Dit is typische code bij het aanroepen van een Java-bibliotheek die mogelijk een nulreferentie retourneert:

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

Als getResource() een null retourneert, is resource een object None . Anders wordt het een Some(resource) object. De voorkeursmanier om een Option te handelen, is gebruik te maken van functies van hogere orde die beschikbaar zijn binnen het Option . Als u bijvoorbeeld wilt controleren of uw waarde niet None (vergelijkbaar met controleren of value == null ), gebruikt u de functie isDefined :

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

Op dezelfde manier, om te controleren of een null referentie kunt u dit doen:

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

Het heeft de voorkeur dat u voorwaardelijke uitvoering behandelt volgens de verpakte waarde van een Option (zonder de 'exceptionele' Option.get methode te gebruiken) door de Option als een monade te behandelen en 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

Als een Resource vereist is (versus een Option[Resource] instantie), kunt u Option nog steeds gebruiken om te beschermen tegen nulwaarden. Hier biedt de methode getOrElse een standaardwaarde:

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

Java-code zal Scala's Option niet gemakkelijk verwerken, dus wanneer waarden aan Java-code worden doorgegeven, is het een goede vorm om een Option te pakken, null of een verstandige standaard indien van toepassing:

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

Basics

Een Option is een gegevensstructuur die een enkele waarde of helemaal geen waarde bevat. Een Option kan worden gezien als verzamelingen van nul of één elementen.

Option is een abstracte klas met twee kinderen: Some en None .

Some bevatten een enkele waarde en None bevat geen waarde.

Option is handig in uitdrukkingen die anders null zouden gebruiken om het ontbreken van een concrete waarde weer te geven. Dit beschermt tegen een NullPointerException en maakt de samenstelling mogelijk van veel expressies die mogelijk geen waarde retourneren met behulp van combinators zoals Map , FlatMap , etc.

Voorbeeld met kaart

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] is verzegeld en kan dus niet worden uitgebreid. Daarom is de semantiek stabiel en kan erop worden vertrouwd.

Opties voor begrip

Option hebben een flatMap methode. Dit betekent dat ze kunnen worden gebruikt in een voor begrip. Op deze manier kunnen we reguliere functies naar Option s tillen zonder ze opnieuw te definiëren.

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)

Als een van de waarden None het eindresultaat van de berekening ook 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

Opmerking: dit patroon is meer algemeen van toepassing op concepten die Monad s worden genoemd. (Meer informatie zou beschikbaar moeten zijn op pagina's met betrekking tot begrip en Monad )

Over het algemeen is het niet mogelijk om verschillende monaden voor een goed begrip te mixen. Maar omdat Option eenvoudig kan worden omgezet in een Iterable , kunnen we Option s en Iterable s gemakkelijk mixen door de .toIterable methode aan te roepen.

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)

Een kleine opmerking: als we ons begrip voor begrip hadden gedefinieerd, zou andersom het begrip bevatten, omdat onze optie impliciet zou worden omgezet. Daarom is het handig om altijd .toIterable (of de bijbehorende functie, afhankelijk van de verzameling die u gebruikt) toe te voegen voor consistentie.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow