¿Cuáles son las características ocultas de Scala que todo desarrollador de Scala debe tener en cuenta?
Una característica oculta por respuesta, por favor.
scala
hidden-features
Krzysiek Goj
fuente
fuente
Respuestas:
Bien, tuve que agregar uno más. Cada
Regex
objeto en Scala tiene un extractor (vea la respuesta de oxbox_lakes arriba) que le da acceso a los grupos de coincidencias. Entonces puedes hacer algo como:La segunda línea parece confusa si no está acostumbrado a usar patrones coincidentes y extractores. Siempre que defina un
val
ovar
, lo que viene después de la palabra clave no es simplemente un identificador sino un patrón. Por eso funciona esto:La expresión de la mano derecha crea un
Tuple3[Int, Double, String]
que puede coincidir con el patrón(a, b, c)
.La mayoría de las veces sus patrones usan extractores que son miembros de objetos singleton. Por ejemplo, si escribes un patrón como
entonces estás llamando implícitamente al extractor
Some.unapply
.Pero también puede usar instancias de clase en patrones, y eso es lo que está sucediendo aquí. Val regex es una instancia de
Regex
, y cuando lo usa en un patrón, está llamando implícitamenteregex.unapplySeq
(unapply
versusunapplySeq
está más allá del alcance de esta respuesta), que extrae los grupos de coincidencia en aSeq[String]
, cuyos elementos se asignan para las variables año, mes y día.fuente
Definiciones de tipo estructural , es decir, un tipo descrito por los métodos que admite. Por ejemplo:
Observe que el tipo del parámetro
closeable
no se define más que si tiene unclose
métodofuente
Polimorfismo de constructor de tipos (también conocido como tipos de tipo superior)
Sin esta característica, puede, por ejemplo, expresar la idea de asignar una función sobre una lista para devolver otra lista, o asignar una función sobre un árbol para devolver otro árbol. Pero no se puede expresar esta idea en general sin clases superiores.
Con tipos más altos, puede capturar la idea de cualquier tipo que esté parametrizado con otro tipo. Se dice que un constructor de tipo que toma un parámetro es de tipo
(*->*)
. Por ejemplo,List
. Se dice que un constructor de tipo que devuelve otro constructor de tipo es de tipo(*->*->*)
. Por ejemplo,Function1
. Pero en Scala, tenemos tipos más altos , por lo que podemos tener constructores de tipos que se parametrizan con otros constructores de tipos. Entonces son de tipo como((*->*)->*)
.Por ejemplo:
Ahora, si tiene un
Functor[List]
, puede asignar sobre listas. Si tiene unFunctor[Tree]
, puede mapear sobre árboles. Pero lo más importante, si tieneFunctor[A]
alguna A de tipo(*->*)
, puede asignar una funciónA
.fuente
Extractores que le permiten reemplazar el
if-elseif-else
código de estilo desordenado con patrones. Sé que estos no están exactamente ocultos, pero he estado usando Scala durante unos meses sin comprender realmente el poder de ellos. Para (un largo) ejemplo, puedo reemplazar:Con esto, que es mucho más claro en mi opinión.
Tengo que hacer un poco de trabajo de fondo en el fondo ...
Pero el trabajo preliminar vale la pena por el hecho de que separa una pieza de lógica empresarial en un lugar sensible. Puedo implementar mis
Product.getCode
métodos de la siguiente manera ...fuente
Manifiestos que son una forma de obtener la información de tipo en tiempo de ejecución, como si Scala hubiera reificado los tipos.
fuente
En scala 2.8 puede tener métodos recursivos de cola utilizando el paquete scala.util.control.TailCalls (de hecho, es trampolín).
Un ejemplo:
fuente
Las clases de casos mezclan automáticamente el rasgo del Producto, proporcionando acceso indexado y sin tipo a los campos sin ninguna reflexión:
Esta característica también proporciona una forma simplificada de alterar la salida del
toString
método:fuente
No está exactamente oculto, pero ciertamente es una característica poco anunciada: scalac -Xprint .
Como ilustración del uso, considere la siguiente fuente:
Compilando esto con scalac -Xprint: salidas typer :
Aviso
scala.this.Predef.augmentString("xx").r
, que es una aplicación delimplicit def augmentString
presente en Predef.scala.scalac -Xprint: <phase> imprimirá el árbol de sintaxis después de alguna fase del compilador. Para ver las fases disponibles, use scalac -Xshow-phase .
Esta es una excelente manera de aprender lo que está sucediendo detrás de escena.
Probar con
case class X(a:Int,b:String)
usando la fase typer para sentir realmente lo útil que es.
fuente
Puede definir sus propias estructuras de control. Realmente son solo funciones y objetos y algo de azúcar sintáctica, pero se ven y se comportan como si fueran reales.
Por ejemplo, el siguiente código define
dont {...} unless (cond)
ydont {...} until (cond)
:Ahora puedes hacer lo siguiente:
fuente
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Requiere Scalaz.@switch
Anotación en Scala 2.8:Ejemplo:
fuente
No sé si esto está realmente oculto, pero me parece bastante agradable.
Los constructores de tipos que toman 2 parámetros de tipo pueden escribirse en notación infija
fuente
var foo2barConverter: Foo ConvertTo Bar
, el orden de los parámetros de tipo sería evidente.Scala 2.8 introdujo argumentos predeterminados y con nombre, lo que hizo posible la adición de un nuevo método de "copia" que Scala agrega a las clases de casos. Si define esto:
y desea crear un nuevo Foo que sea como un Foo existente, solo que con un valor "n" diferente, entonces simplemente puede decir:
fuente
en scala 2.8 puede agregar @specialized a sus clases / métodos genéricos. Esto creará versiones especiales de la clase para tipos primitivos (extendiendo AnyVal) y ahorrará el costo de boxeo / unboxing innecesario:
class Foo[@specialized T]...
Puede seleccionar un subconjunto de AnyVals:
class Foo[@specialized(Int,Boolean) T]...
fuente
Extendiendo el lenguaje. Siempre quise hacer algo así en Java (no pude). Pero en Scala puedo tener:
y luego escribe:
y obten
fuente
Puede designar un parámetro de llamada por nombre (EDITADO: ¡esto es diferente a un parámetro diferido!) A una función y no se evaluará hasta que la función lo use (EDITAR: de hecho, se volverá a evaluar cada vez que se usado). Vea este faq para más detalles
fuente
lazy val xx: Bar = x
en tu método y desde ese momento solo lo usasxx
.Puede usar
locally
para introducir un bloque local sin causar problemas de inferencia de punto y coma.Uso:
locally
se define en "Predef.scala" como:Al estar en línea, no impone ningún gasto adicional.
fuente
Inicialización temprana:
Salida:
fuente
Puede componer tipos estructurales con la palabra clave 'con'
fuente
sintaxis de marcador de posición para funciones anónimas
De la especificación del lenguaje Scala:
De Scala Cambios de idioma :
Usando esto podrías hacer algo como:
fuente
Definiciones implícitas, particularmente conversiones.
Por ejemplo, suponga una función que formateará una cadena de entrada para que se ajuste a un tamaño, reemplazando el centro de la misma con "...":
Puede usar eso con cualquier Cadena y, por supuesto, usar el método toString para convertir cualquier cosa. Pero también podrías escribirlo así:
Y luego, podría pasar clases de otros tipos haciendo esto:
Ahora puedes llamar a esa función pasando un doble:
El último argumento es implícito y se pasa automáticamente debido a la declaración implícita. Además, "s" está siendo tratada como una cadena dentro de sizeBoundedString porque hay una conversión implícita de ella a cadena.
Los impedimentos de este tipo están mejor definidos para tipos poco comunes para evitar conversiones inesperadas. También puede pasar explícitamente una conversión, y todavía se usará implícitamente dentro de sizeBoundedString:
También puede tener múltiples argumentos implícitos, pero luego debe pasarlos todos o no pasar ninguno de ellos. También hay una sintaxis de acceso directo para las conversiones implícitas:
Esto se usa exactamente de la misma manera.
Los implicits pueden tener cualquier valor. Se pueden usar, por ejemplo, para ocultar información de la biblioteca. Tome el siguiente ejemplo, por ejemplo:
En este ejemplo, llamar a "f" en un objeto Y enviará el registro al daemon predeterminado y, en una instancia de X, al daemon X de Daemon. Pero llamar a g en una instancia de X enviará el registro al DefaultDaemon dado explícitamente.
Si bien este ejemplo simple puede reescribirse con sobrecarga y estado privado, las implicaciones no requieren un estado privado y pueden ponerse en contexto con las importaciones.
fuente
Tal vez no esté demasiado oculto, pero creo que esto es útil:
Esto generará automáticamente un getter y setter para el campo que coincida con la convención de bean.
Descripción adicional en developerworks
fuente
Argumentos implícitos en los cierres.
Un argumento de función se puede marcar como implícito al igual que con los métodos. Dentro del alcance del cuerpo de la función, el parámetro implícito es visible y elegible para la resolución implícita:
fuente
Cree estructuras de datos infinitas con los
Stream
s de Scala : http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patientfuente
Los tipos de resultados dependen de la resolución implícita. Esto puede darle una forma de envío múltiple:
fuente
foo
utiliza una
que debe haber estado presente en el entorno antes de la ejecución de estos comandos. Supongo que quisiste decirz.perform(x)
.Equivalente de Scala al inicializador Java de doble paréntesis.
Scala le permite crear una subclase anónima con el cuerpo de la clase (el constructor) que contiene declaraciones para inicializar la instancia de esa clase.
Este patrón es muy útil cuando se crean interfaces de usuario basadas en componentes (por ejemplo, Swing, Vaadin), ya que permite crear componentes de IU y declarar sus propiedades de manera más concisa.
Consulte http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf para obtener más información.
Aquí hay un ejemplo de cómo crear un botón Vaadin:
fuente
Excluir miembros de
import
declaracionesSuponga que desea utilizar un método
Logger
que contenga ayprintln
unprinterr
método, pero solo desea utilizar el que se usa para mensajes de error y mantener el valor antiguoPredef.println
para la salida estándar. Podrías hacer esto:pero si
logger
también contiene otros doce métodos que le gustaría importar y usar, resulta inconveniente enumerarlos. En su lugar, podría intentar:pero esto todavía "contamina" la lista de miembros importados. Ingrese el comodín über-poderoso:
y eso hará lo correcto ™.
fuente
require
Método (definido enPredef
) que le permite definir restricciones de funciones adicionales que se comprobarían durante el tiempo de ejecución. Imagine que está desarrollando otro cliente de Twitter y necesita limitar la longitud del tweet a 140 símbolos. Además, no puedes publicar un tweet vacío.Ahora llamar a post con un argumento de longitud inapropiada causará una excepción:
Puede escribir múltiples requisitos o incluso agregar una descripción a cada uno:
Ahora las excepciones son detalladas:
Un ejemplo más está aquí .
Prima
Puede realizar una acción cada vez que falle el requisito:
fuente
require
No es una palabra reservada. Es solo un método definido enPredef
.Los rasgos con
abstract override
métodos son una característica en Scala que no se anuncia tan ampliamente como muchos otros. La intención de los métodos con elabstract override
modificador es hacer algunas operaciones y delegar la llamada asuper
. Luego, estos rasgos deben mezclarse con implementaciones concretas de susabstract override
métodos.Si bien mi ejemplo no es mucho más que un AOP pobre para hombres, utilicé estos Rasgos apilables para mi gusto para construir instancias de intérpretes Scala con importaciones predefinidas, enlaces personalizados y patrones de clase. Los Rasgos Apilables hicieron posible crear mi fábrica en la línea de
new InterpreterFactory with JsonLibs with LuceneLibs
y luego tener importaciones útiles y variables de alcance para los scripts de los usuarios.fuente