Recherche…


Syntaxe

  • class Some [+ T] (valeur: T) étend Option [T]

  • objet Aucun étend Option [Nothing]

  • Option [T] (valeur: T)

    Constructeur pour créer soit Some(value) ou None selon la valeur fournie.

Options en tant que collections

Option ont des fonctions utiles de niveau supérieur qui peuvent être facilement comprises en affichant les options sous forme de collections avec zéro ou un élément - où None se comporte comme la collection vide et Some(x) se comporte comme une collection avec un seul élément, 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

Utilisation de l'option au lieu de null

En Java (et dans d'autres langages), l'utilisation de null est un moyen courant d'indiquer qu'il n'y a pas de valeur attachée à une variable de référence. Dans Scala, utiliser Option est préférable à l'utilisation de null . Option encapsule les valeurs pouvant être null .

None est une sous-classe de Option enveloppe une référence null. Some est une sous-classe d' Option enveloppant une référence non NULL.

Envelopper une référence est facile:

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

Il s'agit d'un code typique lors de l'appel d'une bibliothèque Java susceptible de renvoyer une référence null:

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

Si getResource() renvoie une valeur null , la resource sera un objet None . Sinon, ce sera un objet Some(resource) . La manière préférée de traiter une Option consiste à utiliser les fonctions d'ordre supérieur disponibles dans le type d' Option . Par exemple, si vous voulez vérifier si votre valeur n'est pas None (similaire à vérifier si la value == null ), vous utiliseriez la fonction isDefined :

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

De même, pour rechercher une référence null vous pouvez le faire:

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

Il est préférable de traiter l'exécution conditionnelle sur la valeur Option.get d'une Option (sans utiliser la méthode Option.get «exceptionnelle») en traitant l' Option comme une monade et en utilisant 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

Si une instance Resource est requise (par rapport à une instance Option[Resource] ), vous pouvez toujours utiliser Option pour vous protéger contre les valeurs NULL. Ici, la méthode getOrElse fournit une valeur par défaut:

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

Le code Java ne gèrera pas facilement l’ Option de Scala, donc lorsqu’il transmet des valeurs au code Java, il est préférable de déballer une Option , en transmettant null ou une valeur par défaut sensible, le cas échéant:

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

Les bases

Une Option est une structure de données contenant une valeur unique ou aucune valeur. Une Option peut être considérée comme une collection de zéro ou d'un élément.

Option est une classe abstraite avec deux enfants: Some et None .

Some contiennent une seule valeur et None ne contient aucune valeur.

Option est utile dans les expressions qui utiliseraient autrement null pour représenter l'absence d'une valeur concrète. Cela protège contre une NullPointerException et permet la composition de nombreuses expressions qui pourraient ne pas renvoyer de valeur en utilisant des combinateurs tels que Map , FlatMap , etc.

Exemple avec carte

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] est scellée et ne peut donc pas être étendue. Par conséquent, sa sémantique est stable et peut être invoquée.

Options pour la compréhension

Option ont une méthode flatMap . Cela signifie qu'ils peuvent être utilisés pour la compréhension. De cette manière, nous pouvons lever des fonctions régulières pour travailler sur Option s sans avoir à les redéfinir.

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)

Lorsque l' une des valeurs est un None résultat de fin du calcul sera None aussi bien.

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

Remarque: ce modèle s’étend plus généralement aux concepts appelés Monad s. (Plus d'informations devraient être disponibles sur les pages relatives à la compréhension et Monad s)

En général, il n'est pas possible de mélanger différentes monades dans une compréhension. Mais comme Option peut être facilement convertie en une Iterable , nous pouvons facilement mélanger Option s et Iterable s en appelant la méthode .toIterable .

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)

Une petite note: si nous avions défini le notre pour la compréhension, la compréhension serait compilée car notre option serait convertie implicitement. Pour cette raison, il est utile de toujours ajouter cette .toIterable (ou fonction correspondante selon la collection que vous utilisez) pour la cohérence.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow