Quais são os recursos ocultos do Scala que todo desenvolvedor de Scala deve conhecer?
Um recurso oculto por resposta, por favor.
scala
hidden-features
Krzysiek Goj
fonte
fonte
Respostas:
Ok, eu tive que adicionar mais um. Todo
Regex
objeto no Scala possui um extrator (veja a resposta de oxbox_lakes acima) que dá acesso aos grupos de correspondência. Então você pode fazer algo como:A segunda linha parece confusa se você não está acostumado a usar correspondência e extratores de padrões. Sempre que você define um
val
ouvar
, o que vem depois da palavra-chave não é simplesmente um identificador, mas um padrão. É por isso que isso funciona:A expressão da mão direita cria um
Tuple3[Int, Double, String]
que pode corresponder ao padrão(a, b, c)
.Na maioria das vezes, seus padrões usam extratores que são membros de objetos singleton. Por exemplo, se você escrever um padrão como
então você está implicitamente chamando o extrator
Some.unapply
.Mas você também pode usar instâncias de classe em padrões, e é isso que está acontecendo aqui. O val regex é uma instância de
Regex
, e quando você o usa em um padrão, você está implicitamente chamandoregex.unapplySeq
(unapply
versusunapplySeq
está além do escopo desta resposta), que extrai os grupos de correspondência em aSeq[String]
, cujos elementos são atribuídos para as variáveis ano, mês e dia.fonte
Definições de tipo estrutural - ou seja, um tipo descrito por quais métodos ele suporta. Por exemplo:
Observe que o tipo do parâmetro
closeable
não está definido, exceto por ter umclose
métodofonte
Polimorfismo de construtor de tipo (também conhecido como tipos com classificação mais alta)
Sem esse recurso, você pode, por exemplo, expressar a idéia de mapear uma função sobre uma lista para retornar outra lista ou mapear uma função sobre uma árvore para retornar outra árvore. Mas você não pode expressar essa ideia geralmente sem tipos mais elevados.
Com tipos mais altos, você pode capturar a ideia de qualquer tipo parametrizado com outro tipo. Diz-se que um construtor de tipos que usa um parâmetro é do tipo
(*->*)
. Por exemploList
,. Diz-se que um construtor de tipos que retorna outro construtor de tipos é do tipo(*->*->*)
. Por exemploFunction1
,. Porém, no Scala, temos tipos mais altos , portanto, podemos ter construtores de tipo que são parametrizados com outros construtores de tipo. Então eles são do tipo((*->*)->*)
.Por exemplo:
Agora, se você tiver um
Functor[List]
, poderá mapear as listas. Se você tiver umFunctor[Tree]
, poderá mapear sobre árvores. Mas o mais importante é que, se você tiverFunctor[A]
algum tipo A(*->*)
, poderá mapear uma funçãoA
.fonte
Extratores que permitem substituir o
if-elseif-else
código de estilo confuso por padrões. Sei que eles não estão exatamente ocultos, mas estou usando o Scala há alguns meses sem realmente entender o poder deles. Para (um longo) exemplo, eu posso substituir:Com isso, que é muito mais claro na minha opinião
Eu tenho que fazer um pouco de trabalho braçal em segundo plano ...
Mas o trabalho braçal vale a pena pelo fato de separar uma parte da lógica de negócios em um local sensato. Eu posso implementar meus
Product.getCode
métodos da seguinte maneira ..fonte
Manifesta que são uma forma de obter as informações de tipo em tempo de execução, como se Scala tivesse reificado tipos.
fonte
No scala 2.8, você pode ter métodos recursivos de cauda usando o pacote scala.util.control.TailCalls (na verdade, é um trampolim).
Um exemplo:
fonte
As classes de caso combinam automaticamente a característica do Produto, fornecendo acesso indexado e sem tipo aos campos sem nenhum reflexo:
Esse recurso também fornece uma maneira simplificada de alterar a saída do
toString
método:fonte
Não é exatamente oculto, mas certamente um recurso sub-anunciado: scalac -Xprint .
Como ilustração do uso, considere a seguinte fonte:
Compilando isso com scalac -Xprint: typer outputs:
Observe
scala.this.Predef.augmentString("xx").r
, que é a aplicação doimplicit def augmentString
presente no Predef.scala.scalac -Xprint: <phase> imprimirá a árvore de sintaxe após alguma fase do compilador. Para ver as fases disponíveis, use scalac -Xshow-phase .
Essa é uma ótima maneira de aprender o que está acontecendo nos bastidores.
Tente com
case class X(a:Int,b:String)
usando a fase typer para realmente sentir como é útil.
fonte
Você pode definir suas próprias estruturas de controle. É realmente apenas funções e objetos e um pouco de açúcar sintático, mas eles parecem e se comportam como a coisa real.
Por exemplo, o código a seguir define
dont {...} unless (cond)
edont {...} until (cond)
:Agora você pode fazer o seguinte:
fonte
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Requer Scalaz.@switch
anotação no Scala 2.8:Exemplo:
fonte
Não sei se isso está realmente oculto, mas acho muito bom.
Os construtores de tipos que usam dois parâmetros de tipo podem ser escritos em notação infix
fonte
var foo2barConverter: Foo ConvertTo Bar
, tornaria evidente a ordem dos parâmetros de tipo.O Scala 2.8 introduziu argumentos padrão e nomeados, o que possibilitou a adição de um novo método de "cópia" que o Scala adiciona às classes de caso. Se você definir isso:
e você deseja criar um novo Foo que seja como um Foo existente, apenas com um valor "n" diferente, basta dizer:
fonte
no scala 2.8, você pode adicionar @specialized às suas classes / métodos genéricos. Isso criará versões especiais da classe para tipos primitivos (estendendo o AnyVal) e economize o custo do boxe / unboxing desnecessário:
class Foo[@specialized T]...
Você pode selecionar um subconjunto de AnyVals:
class Foo[@specialized(Int,Boolean) T]...
fonte
Estendendo o idioma. Eu sempre quis fazer algo assim em Java (não podia). Mas em Scala eu posso ter:
e escreva:
e pegue
fonte
Você pode designar um parâmetro de chamada por nome (EDITADO: é diferente de um parâmetro lento!) Para uma função e não será avaliado até que seja usado pela função (EDIT: na verdade, será reavaliado toda vez que for usava). Veja este FAQ para detalhes
fonte
lazy val xx: Bar = x
no seu método e a partir desse momento você só usarxx
.Você pode usar
locally
para introduzir um bloco local sem causar problemas de inferência de ponto e vírgula.Uso:
locally
é definido em "Predef.scala" como:Estando em linha, ele não impõe nenhuma sobrecarga adicional.
fonte
Inicialização antecipada:
Resultado:
fonte
Você pode compor tipos estruturais com a palavra-chave 'with'
fonte
sintaxe de espaço reservado para funções anônimas
Da especificação da linguagem Scala:
Das alterações de idioma do Scala :
Usando isso, você pode fazer algo como:
fonte
Definições implícitas, principalmente conversões.
Por exemplo, assuma uma função que formate uma sequência de entrada para caber em um tamanho, substituindo o meio por "...":
Você pode usar isso com qualquer String e, é claro, usar o método toString para converter qualquer coisa. Mas você também pode escrever assim:
E então, você pode passar classes de outros tipos fazendo o seguinte:
Agora você pode chamar essa função passando um duplo:
O último argumento está implícito e está sendo passado automaticamente devido à declaração implícita. Além disso, "s" está sendo tratado como uma String dentro de sizeBoundedString porque há uma conversão implícita para String.
Implícitos desse tipo são melhor definidos para tipos incomuns, a fim de evitar conversões inesperadas. Você também pode passar explicitamente uma conversão, e ela ainda será usada implicitamente dentro de sizeBoundedString:
Você também pode ter vários argumentos implícitos, mas deve passar por todos eles ou não por nenhum deles. Há também uma sintaxe de atalho para conversões implícitas:
Isso é usado exatamente da mesma maneira.
Implícitos podem ter qualquer valor. Eles podem ser usados, por exemplo, para ocultar informações da biblioteca. Veja o exemplo a seguir, por exemplo:
Neste exemplo, chamar "f" em um objeto Y enviará o log para o daemon padrão e em uma instância de X para o daemon X do Daemon. Mas chamar g em uma instância do X enviará o log para o DefaultDaemon explicitamente fornecido.
Embora este exemplo simples possa ser reescrito com sobrecarga e estado privado, os implícitos não requerem estado privado e podem ser contextualizados com importações.
fonte
Talvez não seja muito oculto, mas acho que isso é útil:
Isso gerará automaticamente um getter e um setter para o campo que corresponde à convenção do bean.
Descrição adicional em developerworks
fonte
Argumentos implícitos nos fechamentos.
Um argumento de função pode ser marcado como implícito, assim como nos métodos. Dentro do escopo do corpo da função, o parâmetro implícito é visível e elegível para resolução implícita:
fonte
Crie estruturas de dados infinitas com o Scala's
Stream
: http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patientfonte
Os tipos de resultados dependem da resolução implícita. Isso pode fornecer uma forma de envio múltiplo:
fonte
foo
usosa
que devem estar presentes no ambiente antes da execução desses comandos. Eu suponho que você quis dizerz.perform(x)
.O equivalente da Scala ao inicializador de chave dupla Java.
Scala permite criar uma subclasse anônima com o corpo da classe (o construtor) contendo instruções para inicializar a instância dessa classe.
Esse padrão é muito útil ao criar interfaces de usuário baseadas em componentes (por exemplo, Swing, Vaadin), pois permite criar componentes da interface do usuário e declarar suas propriedades de forma mais concisa.
Consulte http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf para obter mais informações.
Aqui está um exemplo de criação de um botão Vaadin:
fonte
Excluindo membros de
import
declaraçõesSuponha que você queira usar um
Logger
que contenha umprintln
e umprinterr
método, mas deseje usar apenas aquele para mensagens de erro e mantenha o bom e velho estiloPredef.println
para a saída padrão. Você poderia fazer isso:mas se
logger
também contiver outros doze métodos que você gostaria de importar e usar, será inconveniente listá-los. Você poderia tentar:mas isso ainda "polui" a lista de membros importados. Digite o curinga super poderoso:
e isso fará a coisa certa ™.
fonte
require
(definido emPredef
) que permite definir restrições adicionais de função que seriam verificadas durante o tempo de execução. Imagine que você está desenvolvendo outro cliente do twitter e precisa limitar o tamanho do tweet até 140 símbolos. Além disso, você não pode postar um tweet vazio.Agora, chamar post com argumento de comprimento inadequado causará uma exceção:
Você pode escrever vários requisitos ou até mesmo adicionar uma descrição a cada um:
Agora as exceções são detalhadas:
Mais um exemplo está aqui .
Bônus
Você pode executar uma ação sempre que o requisito falhar:
fonte
require
não é uma palavra reservada. É apenas um método definido emPredef
.Traços com
abstract override
métodos são um recurso do Scala que não é tão amplamente divulgado como muitos outros. A intenção dos métodos com oabstract override
modificador é executar algumas operações e delegar a chamada parasuper
. Então essas características precisam ser combinadas com implementações concretas de seusabstract override
métodos.Embora meu exemplo não seja muito mais do que um pobre AOP, usei essas características empilháveis para criar instâncias de interpretador Scala com importações predefinidas, ligações personalizadas e caminhos de classe. As características empilháveis tornaram possível criar minha fábrica de acordo com as linhas de
new InterpreterFactory with JsonLibs with LuceneLibs
e, em seguida, ter importações úteis e variáveis de escopo para os scripts dos usuários.fonte