Comprender las opciones en Scala
En este artículo, aprenderemos cómo trabajar con elementos de datos opcionales en Scala. Las Option en Scala nos ayudan a escribir código robusto.
el tipo Option en Scala
Option[T] en un Scala es un contenedor que almacena cero o un valor de un tipo dado. Manejando valores opcionales usando la Option de Scala, podemos asegurar dos cosas:
- Tipo seguridad: Podemos parametrizar los valores opcionales.
- Conciencia funcional: el tipo
Optionproporciona muchas capacidades funcionales que aseguran que se creen menos errores en el programa.
En Scala, una Option[T] está representada por el objeto Some[T] o None[T]. Aquí scala.Option es la clase base que es abstracta y extendida, haciendo que la Option en Scala se comporte como un contenedor.
Recuerda que la clase Option y sus subclases requieren un tipo concreto. Pueden ser explícitos o inferidos como la siguiente sintaxis.
Ejemplo:
val obj1: Option[Int] = None
val obj2 = Some(100)
Aquí obj1 y obj2 son objetos de Option[Int]. Una pregunta común es cómo comprobar si nuestra Option es Some o None.
Para resolver este problema, tenemos las siguientes funciones.
isEmpty: este método devuelvetruesi el objeto esNone.nonEmpty: este método devuelvetruesi el objeto esSome.isDefined: este método devuelvetruesi el objeto esSome.
Recuperar el Valor de la Option en Scala
Podemos usar el método get para recuperar el valor de Option. Si se invoca el método get en un objeto de None, entonces se lanza NoSuchElementException, también conocido como sesgo de éxito.
Código de ejemplo:
val obj1: Option[Int]= ...
val v1 = if (obj1.isDefined)
{
obj1.get
}
else
{
0
}
El código anterior también se puede escribir utilizando la coincidencia de patrones.
Código de ejemplo:
val obj1: Option[Int]= ...
val v1 = obj1 match {
case Some(temp) =>
temp
case None =>
0
}
También tenemos otros métodos como getOrElse y orElse para recuperar valores.
getOrElse: Este método recupera valores si el objeto esSome; de lo contrario, devuelve un valor predeterminado.orElse: Este método recupera valores si el objeto esSome; de lo contrario, devuelve una opciónalternate.
Cuando el valor opcional no está establecido, el método getOrElse es muy útil ya que podemos devolver un valor predeterminado.
Sintaxis:
val v1 = obj1.getOrElse(0)
la Option como Contenedor en Scala
Como hemos visto que Option es un contenedor en Scala para otro valor, así como atravesamos una List de manera similar, podemos atravesar una Option.
Veamos algunos métodos para este contenedor. Sintaxis del método Option.map en Scala:
final def map[Y](f: (X) => Y): Option[Y]
Código de ejemplo:
val obj1: Option[Int] = Some(100)
assert(obj1.map(_.toString).contains("100"))
assert(obj1.map(_ * 2.0).contains(200))
val obj2: Option[Int] = None
assert(obj2.map(_.toString).isEmpty)
En el ejemplo anterior, usamos el método Option.map para convertir los valores contenidos a otro tipo. El método Option.map también podría usarse para afectar el control de flujo del programa.
Código de ejemplo:
val obj1: Option[Int] = Some(10)
val obj2: Option[Int] = None
def mul(n: Int): Int = n * 2
assert(obj1.map(mul).contains(20))
assert(obj2.map(mul).isEmpty)
Aquí creamos dos objetos de Opción[Int], el primer objeto tiene un valor de 10, y el segundo está vacío. Luego definimos un método mul que multiplica la entrada por 2.
Finalmente, mapeamos obj1 y obj2 utilizando el método mul. Mapear obj1 nos da Some(20), y mapear obj2 nos da None.
Una cosa a observar aquí es que en la segunda llamada, obj2.map(mul), el método mul no se llama en absoluto. También podemos controlar el flujo con filtrado.
Tenemos muchos métodos para hacerlo:
filtro: este método devuelveOptionsi el valor deOptionesSomey la función proporcionada devuelvetrue.existe: este método devuelvetruesi laOptionestá configurada y la función suministrada devuelvetrue.forall: Se comporta igual que el métodoexists.
Usando estas funciones, podemos escribir el código de manera muy concisa.
Pongamos un ejemplo en el que encontremos el equipo con la puntuación más alta.
Código de ejemplo:
def highScoringTeam(playerA: Player, playerB: Player, tournament: Tournament): Option[(Player, Int)] =
{ getTopScore(playerA, tournament).foldRight(getTopScore(playerB, tournament)) {
case (playerAInfo, playerBInfo) => playerBInfo.filter {
case (_, scoreB) => scoreB > playerAInfo._2
}.orElse(Some(playerAInfo))
}
}
En el código anterior, hemos aprovechado que las Option se pueden usar como colecciones. La única diferencia es que una opción puede tener como máximo un valor.
