Quelles sont les fonctionnalités cachées de Scala dont chaque développeur Scala devrait être conscient?
Une fonction cachée par réponse, s'il vous plaît.
scala
hidden-features
Krzysiek Goj
la source
la source
Réponses:
D'accord, j'ai dû en ajouter un de plus. Chaque
Regex
objet dans Scala a un extracteur (voir la réponse d'oxbox_lakes ci-dessus) qui vous donne accès aux groupes de correspondance. Vous pouvez donc faire quelque chose comme:La deuxième ligne semble déroutante si vous n'êtes pas habitué à utiliser la correspondance de motifs et les extracteurs. Chaque fois que vous définissez un
val
ouvar
, ce qui vient après le mot-clé n'est pas simplement un identifiant mais plutôt un modèle. C'est pourquoi cela fonctionne:L'expression de droite crée un
Tuple3[Int, Double, String]
qui peut correspondre au modèle(a, b, c)
.La plupart du temps, vos modèles utilisent des extracteurs qui sont membres d'objets singleton. Par exemple, si vous écrivez un modèle comme
alors vous appelez implicitement l'extracteur
Some.unapply
.Mais vous pouvez également utiliser des instances de classe dans des modèles, et c'est ce qui se passe ici. Le val regex est une instance de
Regex
, et lorsque vous l'utilisez dans un modèle, vous appelez implicitementregex.unapplySeq
(unapply
par opposition à ce quiunapplySeq
dépasse la portée de cette réponse), ce qui extrait les groupes de correspondance en aSeq[String]
, dont les éléments sont affectés afin de les variables année, mois et jour.la source
Définitions de type structurel - c'est-à-dire un type décrit par les méthodes qu'il prend en charge. Par exemple:
Notez que le type du paramètre
closeable
n'est défini que s'il a uneclose
méthodela source
Polymorphisme type-constructeur (aka types de type supérieur)
Sans cette fonctionnalité, vous pouvez, par exemple, exprimer l'idée de mapper une fonction sur une liste pour renvoyer une autre liste, ou de mapper une fonction sur un arbre pour renvoyer un autre arbre. Mais vous ne pouvez pas exprimer cette idée de manière générale sans types supérieurs.
Avec les types supérieurs, vous pouvez capturer l'idée de tout type paramétré avec un autre type. Un constructeur de type qui prend un paramètre est dit de type
(*->*)
. Par exempleList
,. Un constructeur de type qui renvoie un autre constructeur de type est dit de type(*->*->*)
. Par exempleFunction1
,. Mais dans Scala, nous avons des types supérieurs , nous pouvons donc avoir des constructeurs de type paramétrés avec d'autres constructeurs de type. Donc, ils sont du genre((*->*)->*)
.Par exemple:
Maintenant, si vous avez un
Functor[List]
, vous pouvez mapper sur des listes. Si vous avez unFunctor[Tree]
, vous pouvez cartographier les arbres. Mais plus important encore, si vous avezFunctor[A]
pour tout type A(*->*)
, vous pouvez mapper une fonctionA
.la source
Extracteurs qui vous permettent de remplacer le
if-elseif-else
code de style désordonné par des modèles. Je sais que ce ne sont pas exactement cachés mais j'utilise Scala depuis quelques mois sans vraiment en comprendre la puissance. Pour un (long) exemple, je peux remplacer:Avec cela, ce qui est beaucoup plus clair à mon avis
Je dois faire un peu de travail en arrière-plan ...
Mais les démarches en valent la peine, car elles séparent un élément de logique métier en un endroit sensible. Je peux implémenter mes
Product.getCode
méthodes comme suit.la source
Manifeste qui est une sorte de moyen d'obtenir les informations de type au moment de l'exécution, comme si Scala avait réifié des types.
la source
Dans scala 2.8, vous pouvez avoir des méthodes récursives de fin en utilisant le package scala.util.control.TailCalls (en fait, il s'agit de trampoline).
Un exemple:
la source
Les classes de cas se mélangent automatiquement dans le trait Product, fournissant un accès non typé et indexé aux champs sans aucune réflexion:
Cette fonctionnalité fournit également un moyen simplifié de modifier la sortie de la
toString
méthode:la source
Ce n'est pas exactement caché, mais certainement une fonctionnalité sous-annoncée: scalac -Xprint .
Pour illustrer l'utilisation, considérons la source suivante:
Compiler cela avec scalac -Xprint: sorties typer :
Remarquez
scala.this.Predef.augmentString("xx").r
, qui est une application duimplicit def augmentString
présent dans Predef.scala.scalac -Xprint: <phase> affichera l'arbre de syntaxe après une phase de compilation. Pour voir les phases disponibles, utilisez scalac -Xshow-phases .
C'est un excellent moyen d'apprendre ce qui se passe dans les coulisses.
Essayez avec
case class X(a:Int,b:String)
en utilisant la phase de frappe pour vraiment sentir à quel point c'est utile.
la source
Vous pouvez définir vos propres structures de contrôle. Ce ne sont vraiment que des fonctions et des objets et du sucre syntaxique, mais ils ressemblent et se comportent comme la vraie chose.
Par exemple, le code suivant définit
dont {...} unless (cond)
etdont {...} until (cond)
:Vous pouvez maintenant effectuer les opérations suivantes:
la source
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Nécessite Scalaz.@switch
annotation dans Scala 2.8:Exemple:
la source
Je ne sais pas si cela est vraiment caché, mais je trouve cela plutôt sympa.
Les constructeurs de types qui prennent 2 paramètres de type peuvent être écrits en notation infixe
la source
var foo2barConverter: Foo ConvertTo Bar
, l'ordre des paramètres de type est évident.Scala 2.8 a introduit des arguments par défaut et nommés, ce qui a rendu possible l'ajout d'une nouvelle méthode "copie" que Scala ajoute aux classes de cas. Si vous définissez ceci:
et vous voulez créer un nouveau Foo qui ressemble à un Foo existant, uniquement avec une valeur "n" différente, alors vous pouvez simplement dire:
la source
dans scala 2.8, vous pouvez ajouter @specialized à vos classes / méthodes génériques. Cela créera des versions spéciales de la classe pour les types primitifs (étendant AnyVal) et économisera le coût d'un boxing / unboxing non nécessaire:
class Foo[@specialized T]...
Vous pouvez sélectionner un sous-ensemble d'AnyVals:
class Foo[@specialized(Int,Boolean) T]...
la source
Extension de la langue. J'ai toujours voulu faire quelque chose comme ça en Java (impossible). Mais dans Scala, je peux avoir:
puis écrivez:
et obtenir
la source
Vous pouvez désigner un paramètre call-by-name (EDITED: c'est différent d'un paramètre paresseux!) À une fonction et il ne sera évalué qu'après utilisation par la fonction (EDIT: en fait, il sera réévalué à chaque fois utilisé). Consultez cette FAQ pour plus de détails
la source
lazy val xx: Bar = x
dans votre méthode et à partir de ce moment, vous n'utilisez quexx
.Vous pouvez utiliser
locally
pour introduire un bloc local sans causer de problèmes d'inférence de point-virgule.Usage:
locally
est défini dans "Predef.scala" comme:Étant en ligne, il n'impose aucune surcharge supplémentaire.
la source
Initialisation précoce:
Production:
la source
Vous pouvez composer des types structurels avec le mot-clé "avec"
la source
syntaxe d'espace réservé pour les fonctions anonymes
À partir de la spécification du langage Scala:
À partir des changements de langue Scala :
En utilisant cela, vous pouvez faire quelque chose comme:
la source
Définitions implicites, en particulier les conversions.
Par exemple, supposons une fonction qui formatera une chaîne d'entrée pour l'adapter à une taille, en remplaçant le milieu de celle-ci par "...":
Vous pouvez l'utiliser avec n'importe quelle chaîne et, bien sûr, utiliser la méthode toString pour convertir n'importe quoi. Mais vous pouvez aussi l'écrire comme ceci:
Et puis, vous pouvez passer des classes d'autres types en faisant ceci:
Vous pouvez maintenant appeler cette fonction en passant un double:
Le dernier argument est implicite et est passé automatiquement en raison de la déclaration implicite de. En outre, "s" est traité comme une chaîne à l'intérieur de sizeBoundedString car il y a une conversion implicite de celui-ci en String.
Les implicits de ce type sont mieux définis pour les types inhabituels afin d'éviter les conversions inattendues. Vous pouvez également passer explicitement une conversion, et elle sera toujours implicitement utilisée dans sizeBoundedString:
Vous pouvez également avoir plusieurs arguments implicites, mais vous devez alors les passer tous ou ne pas les transmettre. Il existe également une syntaxe de raccourci pour les conversions implicites:
Ceci est utilisé exactement de la même manière.
Les implicits peuvent avoir n'importe quelle valeur. Ils peuvent être utilisés, par exemple, pour masquer les informations de la bibliothèque. Prenons l'exemple suivant, par exemple:
Dans cet exemple, appeler "f" dans un objet Y enverra le journal au démon par défaut, et sur une instance de X au démon Daemon X. Mais appeler g sur une instance de X enverra le journal au DefaultDaemon explicitement donné.
Bien que cet exemple simple puisse être réécrit avec une surcharge et un état privé, les implicits ne nécessitent pas d'état privé et peuvent être mis en contexte avec les importations.
la source
Peut-être pas trop caché, mais je pense que c'est utile:
Cela générera automatiquement un getter et un setter pour le champ qui correspond à la convention du bean.
Description supplémentaire chez developerworks
la source
Arguments implicites dans les fermetures.
Un argument de fonction peut être marqué comme implicite comme avec les méthodes. Dans le cadre du corps de la fonction, le paramètre implicite est visible et éligible pour une résolution implicite:
la source
Construisez des structures de données infinies avec les Scala
Stream
: http://www.codecommit.com/blog/scala/infinite-lists-for-the-finately-patientla source
Les types de résultats dépendent de la résolution implicite. Cela peut vous donner une forme d'envoi multiple:
la source
foo
usages eta
qui doivent avoir été présents dans l'environnement avant l'exécution de ces commandes. Je suppose que vous vouliez direz.perform(x)
.L'équivalent de Scala de l'initialiseur Java à double accolade.
Scala vous permet de créer une sous-classe anonyme avec le corps de la classe (le constructeur) contenant des instructions pour initialiser l'instance de cette classe.
Ce modèle est très utile lors de la construction d'interfaces utilisateur basées sur des composants (par exemple Swing, Vaadin) car il permet de créer des composants d'interface utilisateur et de déclarer leurs propriétés de manière plus concise.
Voir http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf pour plus d'informations.
Voici un exemple de création d'un bouton Vaadin:
la source
Exclure des membres des
import
déclarationsSupposons que vous souhaitiez utiliser une
Logger
qui contient une méthodeprintln
et uneprinterr
, mais que vous ne souhaitiez utiliser que celle pour les messages d'erreur et conserver la bonne vieillePredef.println
pour la sortie standard. Vous pouvez faire ceci:mais si
logger
contient également douze autres méthodes que vous souhaitez importer et utiliser, il devient peu pratique de les lister. Vous pouvez à la place essayer:mais cela «pollue» toujours la liste des membres importés. Entrez le joker über-puissant:
et cela fera ce qu'il faut ™.
la source
require
méthode (définie dansPredef
) qui vous permet de définir des contraintes de fonction supplémentaires qui seraient vérifiées lors de l'exécution. Imaginez que vous développiez un autre client Twitter et que vous deviez limiter la longueur des tweets à 140 symboles. De plus, vous ne pouvez pas publier de tweet vide.Maintenant, appeler post avec un argument de longueur inapproprié provoquera une exception:
Vous pouvez rédiger plusieurs exigences ou même ajouter une description à chacune:
Maintenant, les exceptions sont verbeuses:
Un autre exemple est ici .
Prime
Vous pouvez effectuer une action chaque fois que l'exigence échoue:
la source
require
n'est pas un mot réservé. Ce n'est qu'une méthode définie dansPredef
.Les traits avec des
abstract override
méthodes sont une fonctionnalité de Scala qui n'est pas aussi largement annoncée que beaucoup d'autres. Le but des méthodes avec leabstract override
modificateur est d'effectuer certaines opérations et de déléguer l'appel àsuper
. Ensuite, ces traits doivent être mélangés avec des implémentations concrètes de leursabstract override
méthodes.Bien que mon exemple ne soit vraiment pas beaucoup plus qu'un AOP pour homme pauvre, j'ai utilisé ces traits empilables à mon goût pour créer des instances d'interpréteur Scala avec des importations prédéfinies, des liaisons personnalisées et des chemins de classe. Les traits empilables ont permis de créer mon usine le long des lignes de
new InterpreterFactory with JsonLibs with LuceneLibs
puis d'avoir des importations et des variables de portée utiles pour les scripts des utilisateurs.la source