martes, 20 de febrero de 2018

Un resumen de Scala for the Impatient, parte 37


Los métodos apply y update

En scala podemos extender la sintaxis de llamada de funciones :

f(n1, n2, n3, …)

Si f es una función o un método, se ejecuta. De lo contrario, se llama al método apply por lo tanto es equivalente a llamar a

f.apply(n1, n2, n3, …)

De la misma manera si se utiliza la notación de función con asignación se llama al método update :

f(n1, n2, n3, …) = value

Es similar a llamar a :

f.update(n1, n2, n3, …, value)

Este mecanismo es utilizado en arrays y maps :

val scores = new scala.collection.mutable.HashMap[String, Int]
scores("Bob") = 100 // es como llamar a scores.update("Bob", 100)
val bobsScore = scores("Bob") // es como llamar a scores.apply("Bob")

El método apply también es usado para retornar instancias de objetos, sin tener que llamar al constructor con el new :

class Fraction(n: Int, d: Int) {

}

object Fraction {
def apply(n: Int, d: Int) = new Fraction(n, d)
}

De esta manera podemos hacer lo siguiente:

val result = Fraction(3, 4) * Fraction(2, 5)

Extractors

Un extractor es un objeto que puede desaplicar un método. Se puede pensar esto como el método contrario a el apply. Por ejemplo si el apply agrega un elemento a una lista el extractor debería quitar este elemento.

Por ejemplo el objeto Fraction tiene un método apply que retorna una Fraction a partir de un numerador y un denominador. El extractor debería retornar un numerador y un denominador a partir de una Fraction.

object Fraction {
def unapply(input: Fraction) =
if (input.den == 0) None else Some((input.num, input.den))
}

Por lo general el método unapply retorna un Option dado que puede haber un error cuando queremos desaplicar un método. En el ejemplo si el denominador es 0 retorna None.

val Fraction(a, b) = f;
val tupleOption = Fraction.unapply(f)
if (tupleOption == None) throw new MatchError
// tupleOption is Some((t1 , t2))

En el ejemplo el método apply y unapply son inversos pero esto no es obligatorio.