149 votos

Características ocultas de Scala

¿Cuáles son las características ocultas de Scala que todos los desarrolladores Scala debe tener en cuenta?

Una característica oculta por respuesta, por favor.

85voto

Willis Blackburn Puntos 980

Bueno, he tenido que añadir una más. Cada Regex objeto en la Scala dispone de un extractor (véase la respuesta de oxbox_lakes arriba) que les da acceso a la coincidencia de los grupos. Así que usted puede hacer algo como:

// Regex to split a date in the format Y/M/D.
val regex = "(\\d+)/(\\d+)/(\\d+)".r
val regex(year, month, day) = "2010/1/13"

La segunda línea es confuso si usted no está acostumbrado al uso de coincidencia de patrón y extractores. Cuando se define un val o var, lo que viene después de la palabra clave no es simplemente un identificador sino más bien un patrón. Esa es la razón por la que esto funciona:

val (a, b, c) = (1, 3.14159, "Hello, world")

La mano derecha de expresión crea un Tuple3[Int, Double, String] que puede coincidir con el patrón (a, b, c).

La mayoría de las veces sus patrones de uso de extractores que son miembros de los objetos singleton. Por ejemplo, si usted escribe un patrón de

Some(value)

entonces usted está implícitamente llamar a la extractor Some.unapply.

Pero también se puede utilizar instancias de la clase de los patrones, y que es lo que sucede aquí. El val regex es una instancia de Regex, y cuando se utiliza en un patrón, estás implícitamente llamando regex.unapplySeq (unapply versus unapplySeq está más allá del alcance de esta respuesta), que extrae el partido de los grupos en un Seq[String], los elementos de los cuales se asignan en orden a las variables : año, mes, y día.

51voto

oxbow_lakes Puntos 70013

Definiciones de tipos estructurales -, es decir, un tipo descrito por lo que los métodos que soporta. Por ejemplo:

 object Closer {
    def using(closeable: { def close(): Unit }, f: => Unit) {
      try { 
        f
      } finally { closeable.close }
    }
}
 

Observe que el tipo del parámetro closeable no se define aparte de que tiene un close método

45voto

Apocalisp Puntos 22526

Tipo de Constructor de Polimorfismo (a.k.a. mayor-kinded tipos)

Sin esta característica, se puede, por ejemplo, expresa la idea de la asignación de una función a través de una lista de devolver otro de la lista, o la asignación de una función sobre un árbol para volver a otro árbol. Pero no se puede expresar esta idea general, sin mayor tipo.

Con más tipos, usted puede capturar la idea de cualquier tipo que parametrizarse con otro tipo. Un tipo de constructor que toma un parámetro es de tipo (*->*). Por ejemplo, List. Un constructor de tipo que devuelve otro tipo de constructor se dice que es de tipo (*->*->*). Por ejemplo, Function1. Pero en Scala, tenemos más tipos, así que podemos tener los constructores de tipos que están parametrizados con otro tipo de constructores. Así que son de tipos como ((*->*)->*).

Por ejemplo:

trait Functor[F[_]] {
  def fmap[A, B](f: A => B, fa: F[A]): F[B]
}

Ahora, si usted tiene un Functor[List], puede asignar más listas. Si usted tiene un Functor[Tree], puede asignar los árboles. Pero lo que es más importante, si usted tiene Functor[A] para cualquier tipo de (*->*), puede asignar una función más de A.

39voto

oxbow_lakes Puntos 70013

Extractores que le permiten sustituir desordenado if-elseif-else código de estilo con los patrones. Sé que estos no son exactamente oculto , pero yo he estado usando la Scala de un par de meses sin realmente entender el poder de ellos. (Un tiempo) ejemplo puedo reemplazar:

val code: String = ...
val ps: ProductService = ...
var p: Product = null
if (code.endsWith("=")) {
  p = ps.findCash(code.substring(0, 3)) //e.g. USD=, GBP= etc
}
else if (code.endsWith(".FWD")) {
  //e.g. GBP20090625.FWD
  p = ps.findForward(code.substring(0,3), code.substring(3, 9))
}
else {
  p = ps.lookupProductByRic(code)
}

Con esto, que es mucho más claro en mi opinión

implicit val ps: ProductService = ...
val p = code match {
  case SyntheticCodes.Cash(c) => c
  case SyntheticCodes.Forward(f) => f
  case _ => ps.lookupProductByRic(code)
}

Tengo que hacer un poco de trabajo de campo en el fondo...

object SyntheticCodes {
  // Synthetic Code for a CashProduct
  object Cash extends (CashProduct => String) {
    def apply(p: CashProduct) = p.currency.name + "="

    //EXTRACTOR
    def unapply(s: String)(implicit ps: ProductService): Option[CashProduct] = {
      if (s.endsWith("=") 
        Some(ps.findCash(s.substring(0,3))) 
      else None
    }
  }
  //Synthetic Code for a ForwardProduct
  object Forward extends (ForwardProduct => String) {
    def apply(p: ForwardProduct) = p.currency.name + p.date.toString + ".FWD"

    //EXTRACTOR
    def unapply(s: String)(implicit ps: ProductService): Option[ForwardProduct] = {
      if (s.endsWith(".FWD") 
        Some(ps.findForward(s.substring(0,3), s.substring(3, 9)) 
      else None
    }
  }

Pero el trabajo de campo es la pena por el hecho de que se separa una parte de la lógica de negocio en un lugar razonable. Puedo aplicar mi Product.getCode métodos de la siguiente manera..

class CashProduct {
  def getCode = SyntheticCodes.Cash(this)
}

class ForwardProduct {
  def getCode = SyntheticCodes.Forward(this)     
}

35voto

oxbow_lakes Puntos 70013

Manifiesta que son una especie de camino en conseguir la información de tipo en tiempo de ejecución, como si Scala había cosificado tipos.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X