miércoles, 28 de febrero de 2018

Un resumen de Scala for the Impatient, parte 38


Extractors con un argumento o ninguno.

Si un unapply método extrae un solo valor este debe retornar un Optional por ejemplo: 


object Number {
def unapply(input: String): Option[Int] =
try {
Some(input.trim.toInt)
} catch {
case ex: NumberFormatException => None
}
}

Con este extractor podemos extraer el numero de un string :

val Number(n) = "1729"

Un extractor puede chequear un valor en este caso debe retornar un booleano:

object IsCompound {
def unapply(input: String) = input.contains(" ")
}


Se puede utilizar un extractor para agregar un test en una expresión pattern matching:


author match {
    case Name(first, IsCompound()) => …
    case Name(first, last) => …

 }

El método unapplySeq

Si utilizamos el extract en una secuencia, estaremos llamando a unapplySeq que retorna Option[Seq[A]] , donde A es el valor extraído:

object Name {
def unapplySeq(input: String): Option[Seq[String]] =
if (input.trim == "") None else Some(input.trim.split("\\s+"))
}


Dado este método ahora podemos utilizar un conjunto de parámetros:

author match {
   case Name(first, last) => …
   case Name(first, middle, last) => …
   case Name(first, “van”, “der”, last) => ...
}

Ojo, no se puede tener un método unapply y un unapplySeq con similar parámetros. 

Invocación dinámica

Scala es un lenguaje de tipado estático y fuertemente tipado.  Es decir que informa los errores de tipo en momento de compilación.

Si un tipo extiende de el trait scala.Dynamic, entonces el método llamadas, getters y setters se reescriben como llamadas a métodos especiales que pueden inspeccionar el nombre de la llamada original y los parámetros, y luego tomar acciones arbitrarias.

Veamos algunos ejemplos. Supongamos que la persona es una instancia de un tipo que se extiende
de Dynamic. Una declaración:

person.lastName = "Doe"

se puede remplazar:

person.updateDynamic ("lastName") ("Doe")

La clase Person debe tener dicho método:

clase Persona {
    ...
    def updateDynamic (campo: String) (newValue: String) {...}
}

Depende de nosotros si implementamos el método updateDynamic.

Otro ejemplo:

val name = person.lastName

puede ser remplazado por:

val name = name.selectDynamic("lastName")

El metodo selectDynamic debe retornar un valor simple. 

En scala existe DynamicProps que extiende a Dynamic y sobre escribe sus métodos:

class DynamicProps(val props: java.util.Properties) extends Dynamic {
    def updateDynamic(name: String)(value: String) {
        props.setProperty(name.replaceAll("_", "."), value)
    }

    def selectDynamic(name: String) =
        props.getProperty(name.replaceAll("_", "."))
    }
}