Caractéristiques cachées de Scala

quelles sont les caractéristiques cachées de Scala que chaque développeur Scala devrait connaître?

une caractéristique cachée par réponse, s'il vous plaît.

149
demandé sur Krzysiek Goj 2009-06-22 05:05:03
la source

28 ответов

OK, j'ai dû en ajouter un de plus. Chaque objet Regex dans Scala a un extracteur (voir la réponse de oxbox_lakes ci-dessus) qui vous donne accès aux groupes de correspondance. Donc vous pouvez faire quelque chose comme:

// 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 deuxième ligne semble déroutante si vous n'êtes pas habitué à l'utilisation de l'appariement des motifs et des extracteurs. Chaque fois que vous définissez un val ou var , ce qui vient après le mot-clé n'est pas simplement un identifiant mais plutôt un motif. C'est pourquoi ce œuvres:

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

l'expression de la main droite crée un Tuple3[Int, Double, String] qui peut correspondre au motif (a, b, c) .

la plupart du temps, vos motifs utilisent des extracteurs qui sont membres d'objets singleton. Par exemple, si vous écrivez un modèle comme

Some(value)

alors vous appelez implicitement l'extracteur Some.unapply .

mais vous pouvez également utiliser des instances de classe dans patterns, et c'est ce qui se passe ici. Le Val regex est une instance de Regex , et quand vous l'utilisez dans un motif, vous appelez implicitement regex.unapplySeq ( unapply versus unapplySeq est au-delà de la portée de cette réponse), qui extrait les groupes de correspondance dans un Seq[String] , dont les éléments sont assignés en ordre aux variables année, mois, et jour.

85
répondu Willis Blackburn 2011-08-17 16:19:10
la source

définition de type de structure - c.-à-d. un type décrit par les méthodes qu'il supporte. Par exemple:

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

notez que le type du paramètre closeable n'est pas défini autrement qu'il a une close méthode

51
répondu oxbow_lakes 2009-07-07 22:22:11
la source

Type-Constructor Polymorphism (A. K. A. 1519140920"

sans cette fonctionnalité, vous pouvez, par exemple, exprimer l'idée de mapper une fonction sur une liste pour retourner une autre liste, ou mapper une fonction sur un arbre pour retourner un autre arbre. Mais vous ne pouvez pas exprimer cette idée généralement sans types supérieurs.

avec des types plus élevés, 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 être de type (*->*) . Par exemple, List . Un constructeur de type qui renvoie un autre constructeur de type est dit être de nature (*->*->*) . Par exemple, Function1 . Mais dans Scala, nous avons des types plus élevés , de sorte que nous pouvons avoir des constructeurs de type qui sont paramétrés avec d'autres constructeurs de type. Ils sont du genre ((*->*)->*) .

par exemple:

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

maintenant , si vous avez un Functor[List] , vous pouvez cartographier les listes. Si vous avez un Functor[Tree] , vous pouvez cartographier les arbres. Mais plus important encore , si vous avez Functor[A] pour tout type de (*->*) , vous pouvez mapper une fonction sur A .

45
répondu Apocalisp 2009-08-04 19:18:27
la source

Extracteurs qui vous permettent de remplacer messy if-elseif-else code de style avec des modèles. Je sais que ce ne sont pas exactement caché mais J'ai utilisé Scala pendant quelques mois sans vraiment comprendre la puissance d'eux. Pour (un long) exemple je peux remplacer:

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)
}

avec ceci, qui est beaucoup plus clair à mon avis

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

je dois faire un peu des démarches dans l'arrière-plan...

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
    }
  }

, Mais l'effort en vaut la peine pour le fait qu'il sépare un morceau de logique métier dans un endroit raisonnable. Je peux implémenter mes méthodes Product.getCode comme suit..

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

class ForwardProduct {
  def getCode = SyntheticCodes.Forward(this)     
}
39
répondu oxbow_lakes 2012-01-29 05:26:30
la source

manifeste qui sont une sorte de moyen pour obtenir les informations de type à l'exécution, comme si Scala avait reifié les types.

35
répondu oxbow_lakes 2009-06-22 10:55:21
la source

dans scala 2.8 vous pouvez avoir des méthodes récursives de queue en utilisant le paquet scala.util.contrôle.TailCalls (en fait c'est le trampolining).

un exemple:

def u(n:Int):TailRec[Int] = {
  if (n==0) done(1)
  else tailcall(v(n/2))
}
def v(n:Int):TailRec[Int] = {
  if (n==0) done(5)
  else tailcall(u(n-1))
}
val l=for(n<-0 to 5) yield (n,u(n).result,v(n).result)
println(l)
35
répondu Aymen 2010-05-18 04:10:47
la source

les classes de cas se mélangent automatiquement dans le caractère du produit, fournissant un accès indexé non typé aux champs sans aucune réflexion:

case class Person(name: String, age: Int)

val p = Person("Aaron", 28)
val name = p.productElement(0) // name = "Aaron": Any
val age = p.productElement(1) // age = 28: Any
val fields = p.productIterator.toList // fields = List[Any]("Aaron", 28)

cette caractéristique fournit également un moyen simplifié de modifier la sortie de la méthode toString :

case class Person(name: String, age: Int) {
   override def productPrefix = "person: "
}

// prints "person: (Aaron,28)" instead of "Person(Aaron, 28)"
println(Person("Aaron", 28)) 
35
répondu Aaron Novstrup 2010-10-30 00:56:45
la source

Ce n'est pas vraiment caché, mais certainement une sous fonction publiée: scalac -Xprint .

comme illustration de l'utilisation considérer la source suivante:

class A { "xx".r }

compilant avec scalac-Xprint: taper sorties:

package <empty> {
  class A extends java.lang.Object with ScalaObject {
    def this(): A = {
      A.super.this();
      ()
    };
    scala.this.Predef.augmentString("xx").r
  }
}

Notice scala.this.Predef.augmentString("xx").r , qui est une application du implicit def augmentString présent dans Predef.Scala.

scalac-Xprint: affichera l'arbre de syntaxe après une certaine phase de compilation. Pour voir les phases disponibles utiliser scalac-xshow-phases .

C'est une excellente façon d'apprendre ce qui se passe derrière les coulisses.

Essayez avec

case class X(a:Int,b:String)

en utilisant la phase typographique pour vraiment sentir à quel point il est utile.

33
répondu pedrofurla 2010-10-26 16:41:16
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) et dont {...} until (cond) :

def dont(code: => Unit) = new DontCommand(code)

class DontCommand(code: => Unit) {
  def unless(condition: => Boolean) =
    if (condition) code

  def until(condition: => Boolean) = {
    while (!condition) {}
    code
  }
}

Maintenant vous pouvez faire ce qui suit:

/* This will only get executed if the condition is true */
dont {
  println("Yep, 2 really is greater than 1.")
} unless (2 > 1) 

/* Just a helper function */
var number = 0;
def nextNumber() = {
  number += 1
  println(number)
  number
}

/* This will not be printed until the condition is met. */
dont {
  println("Done counting to 5!")
} until (nextNumber() == 5) 
30
répondu Aleksander Kmetec 2010-10-30 00:36:10
la source

@switch annotation dans Scala 2.8:

une annotation à appliquer à une correspondance expression. Dans ce cas, le compilateur vérifiera que la correspondance a été compilé à un tableswitch ou rechercher Switch, et émettre une erreur si elle au lieu de cela compile en une série de les expressions conditionnelles.

exemple:

scala> val n = 3
n: Int = 3

scala> import annotation.switch
import annotation.switch

scala> val s = (n: @switch) match {
     |   case 3 => "Three"
     |   case _ => "NoThree"
     | }
<console>:6: error: could not emit switch for @switch annotated match
       val s = (n: @switch) match {
26
répondu missingfaktor 2010-10-20 11:49:31
la source

je ne sais pas si c'est vraiment caché, mais je trouve ça plutôt sympa.

les types de constructeurs qui prennent 2 paramètres de type peuvent être écrits en notation infix

object Main {                                                                   
  class FooBar[A, B]

  def main(args: Array[String]): Unit = {
    var x: FooBar[Int, BigInt] = null
    var y: Int FooBar BigInt   = null
  }
}
26
répondu raichoo 2010-11-30 23:46:07
la source

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 de "copie" que Scala ajoute aux classes de cas. Si vous définissez ceci:

case class Foo(a: Int, b: Int, c: Int, ... z:Int)

et vous voulez créer un nouveau Foo qui est comme un Foo existant, seulement avec une valeur "n" différente, alors vous pouvez juste dire:

foo.copy(n = 3)
24
répondu Willis Blackburn 2010-01-14 00:08:07
la source

dans scala 2.8 vous pouvez ajouter @specialized à vos classes/méthodes génériques. Cela permettra de créer des versions spéciales de la classe pour les types primitifs (extension AnyVal) et d'économiser le coût de la non-nécessaire boxe / Unbox : class Foo[@specialized T]...

vous pouvez sélectionner un sous-ensemble de AnyVals : class Foo[@specialized(Int,Boolean) T]...

24
répondu Aymen 2010-06-20 19:27:33
la source

l'Extension de la langue. J'ai toujours voulu faire quelque chose comme ça à Java (Je ne pouvais pas). Mais à Scala je peux avoir:

  def timed[T](thunk: => T) = {
    val t1 = System.nanoTime
    val ret = thunk
    val time = System.nanoTime - t1
    println("Executed in: " + time/1000000.0 + " millisec")
    ret
  }

et ensuite écrire:

val numbers = List(12, 42, 3, 11, 6, 3, 77, 44)
val sorted = timed {   // "timed" is a new "keyword"!
  numbers.sortWith(_<_)
}
println(sorted)

et obtenir

Executed in: 6.410311 millisec
List(3, 3, 6, 11, 12, 42, 44, 77)
23
répondu Adrian 2010-11-24 20:33:17
la source

vous pouvez désigner un paramètre appel par nom (édité: c'est différent d'un paramètre paresseux!) à une fonction et il ne sera pas évalué jusqu'utilisé par la fonction (EDIT: en fait, il sera réévaluée à chaque fois qu'il est utilisé). Voir cette faq pour plus de détails

class Bar(i:Int) {
    println("constructing bar " + i)
    override def toString():String = {
        "bar with value: " + i
    }
}

// NOTE the => in the method declaration.  It indicates a lazy paramter
def foo(x: => Bar) = {
    println("foo called")
    println("bar: " + x)
}


foo(new Bar(22))

/*
prints the following:
foo called
constructing bar 22
bar with value: 22
*/
23
répondu agilefall 2011-08-18 00:28:45
la source

vous pouvez utiliser locally pour introduire un bloc local sans causer de problèmes d'inférence de point-virgule.

Utilisation:

scala> case class Dog(name: String) {
     |   def bark() {
     |     println("Bow Vow")
     |   }
     | }
defined class Dog

scala> val d = Dog("Barnie")
d: Dog = Dog(Barnie)

scala> locally {
     |   import d._
     |   bark()
     |   bark()
     | }
Bow Vow
Bow Vow

locally est défini dans "Predef.scala":

@inline def locally[T](x: T): T = x

étant en ligne, il n'impose pas de frais généraux supplémentaires.

20
répondu missingfaktor 2010-08-23 14:15:26
la source

Au Début De L'Initialisation:

trait AbstractT2 {
  println("In AbstractT2:")
  val value: Int
  val inverse = 1.0/value
  println("AbstractT2: value = "+value+", inverse = "+inverse)
}

val c2c = new {
  // Only initializations are allowed in pre-init. blocks.
  // println("In c2c:")
  val value = 10
} with AbstractT2

println("c2c.value = "+c2c.value+", inverse = "+c2c.inverse)

sortie:

In AbstractT2:  
AbstractT2: value = 10, inverse = 0.1  
c2c.value = 10, inverse = 0.1

nous instantiate un anonyme intérieur classe, initialisation du champ value dans le bloc, avant la clause with AbstractT2 . Cela garantit value est initialisé avant le corps de AbstractT2 est exécuté, comme affiche lorsque vous exécutez le script.

17
répondu missingfaktor 2010-10-20 11:46:08
la source

vous pouvez composer des types structurels avec le mot-clé "with

object Main {
  type A = {def foo: Unit}
  type B = {def bar: Unit}

  type C = A with B

  class myA {
    def foo: Unit = println("myA.foo")
  }


  class myB {
    def bar: Unit = println("myB.bar")
  }
  class myC extends myB {
    def foo: Unit = println("myC.foo")
  }

  def main(args: Array[String]): Unit = { 
    val a: A = new myA 
    a.foo
    val b: C = new myC 
    b.bar
    b.foo
  }
}
17
répondu raichoo 2010-11-30 11:30:21
la source

syntaxe des espaces réservés pour les fonctions anonymes

De La Spécification De Langue Scala:

SimpleExpr1 ::= '_'

une expression (de la catégorie syntaxique Expr ) peut contenir les symboles de soulignement intégrés _ aux endroits où les identificateurs sont légaux. Une telle expression représente une fonction anonyme où les occurrences subséquentes de underscores indiquent des paramètres successifs.

À Partir De Scala Changements De Langue :

_ + 1                  x => x + 1
_ * _                  (x1, x2) => x1 * x2
(_: Int) * 2           (x: Int) => x * 2
if (_) x else y        z => if (z) x else y
_.map(f)               x => x.map(f)
_.map(_ + 1)           x => x.map(y => y + 1)

en utilisant ceci vous pourriez faire quelque chose comme:

def filesEnding(query: String) =
  filesMatching(_.endsWith(query))
17
répondu Eugene Yokota 2012-01-29 18:41:42
la source

definitions implicites, particularly conversions.

par exemple, supposons une fonction qui formatera une chaîne de caractères pour s'adapter à une taille, en remplaçant le milieu par"...":

def sizeBoundedString(s: String, n: Int): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

vous pouvez utiliser cela 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:

def sizeBoundedString[T](s: T, n: Int)(implicit toStr: T => String): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

Et puis, vous pourriez passer des classes d'autres types en faisant cela:

implicit def double2String(d: Double) = d.toString

maintenant vous pouvez appeler cette fonction passant un double:

sizeBoundedString(12345.12345D, 8)

le dernier argument est implicite, et est passé automatiquement en raison de la déclaration implicite. En outre, "s "est traité comme une chaîne à l'intérieur sizeBoundedString parce qu'il ya une conversion implicite de celui-ci en chaîne.

Implicites de ce type sont mieux définis pour les types rares à éviter conversions inattendues. Vous pouvez également passer explicitement une conversion, et il sera encore implicitement utilisé à l'intérieur de sizeBoundedString:

sizeBoundedString(1234567890L, 8)((l : Long) => l.toString)

vous pouvez aussi avoir plusieurs arguments implicites, mais alors vous devez soit les passer tous, ou ne passer aucun d'entre eux. Il y a aussi une syntaxe de raccourci pour les conversions implicites:

def sizeBoundedString[T <% String](s: T, n: Int): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

utilisé exactement de la même façon.

Implicites peuvent avoir une valeur quelconque. Ils peuvent être utilisés, par exemple, pour cacher des informations de bibliothèque. Prenez l'exemple suivant, par exemple:

case class Daemon(name: String) {
  def log(msg: String) = println(name+": "+msg)
}

object DefaultDaemon extends Daemon("Default")

trait Logger {
  private var logd: Option[Daemon] = None
  implicit def daemon: Daemon = logd getOrElse DefaultDaemon

  def logTo(daemon: Daemon) = 
    if (logd == None) logd = Some(daemon) 
    else throw new IllegalArgumentException

  def log(msg: String)(implicit daemon: Daemon) = daemon.log(msg)
}

class X extends Logger {
  logTo(Daemon("X Daemon"))

  def f = {
    log("f called")
    println("Stuff")
  }

  def g = {
    log("g called")(DefaultDaemon)
  }
}

class Y extends Logger {
  def f = {
    log("f called")
    println("Stuff")
  }
}

dans cet exemple, appeler" f " dans un objet Y enverra le log au démon par défaut, et sur une instance de X au démon X du démon. Mais appeler g sur une instance de X enverra le log au DefaultDaemon explicitement indiqué.

bien que cet exemple simple puisse être réécrit avec surcharge et état privé, implicits ne nécessitent pas État privé, et peut être mis en contexte avec les importations.

16
répondu Daniel C. Sobral 2009-07-07 22:24:42
la source

Peut-être pas trop caché, mais je pense que c'est utile:

@scala.reflect.BeanProperty
var firstName:String = _

cela générera automatiquement un getter et un setter pour le champ correspondant à la Convention bean.

description supplémentaire à developerworks

13
répondu agilefall 2009-06-24 00:06:44
la source

Implicite arguments dans les fermetures.

un argument de fonction peut être marqué aussi implicite comme avec des méthodes. Dans le cadre du corps de la fonction implicite paramètre est visible et éligibles pour la résolution implicite:

trait Foo { def bar }

trait Base {
  def callBar(implicit foo: Foo) = foo.bar
}

object Test extends Base {
  val f: Foo => Unit = { implicit foo =>
    callBar
  }
  def test = f(new Foo {
    def bar = println("Hello")
  })
}
13
répondu axel22 2011-02-16 13:19:39
la source

construire des structures de données infinies avec Stream s de Scala : http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient

12
répondu Aymen 2010-06-24 20:15:50
la source
Les types de résultats

dépendent de la résolution implicite. Cela peut vous donner une forme d'expédition multiple:

scala> trait PerformFunc[A,B] { def perform(a : A) : B }
defined trait PerformFunc

scala> implicit val stringToInt = new PerformFunc[String,Int] {
  def perform(a : String)  = 5
}
stringToInt: java.lang.Object with PerformFunc[String,Int] = [email protected]

scala> implicit val intToDouble = new PerformFunc[Int,Double] {
  def perform(a : Int) = 1.0
}
intToDouble: java.lang.Object with PerformFunc[Int,Double] = [email protected]

scala> def foo[A, B](x : A)(implicit z : PerformFunc[A,B]) : B = z.perform(x)
foo: [A,B](x: A)(implicit z: PerformFunc[A,B])B

scala> foo("HAI")
res16: Int = 5

scala> foo(1)
res17: Double = 1.0
12
répondu jsuereth 2010-08-13 19:46:13
la source

L'équivalent de Scala de Java double brace initialiseur.

Scala vous permet de créer une sous-classe anonyme avec le corps de la classe (le constructeur) contenant des déclarations 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 UI et de déclarer leurs propriétés de manière plus concise.

voir http://spot.colorado.edu/~reid/documents/comment-scala-expérience-amélioration de l'-notre-java-développement-reid-2011.pdf pour plus d'informations.

voici un exemple de création D'un bouton Vaadin:

val button = new Button("Click me"){
 setWidth("20px")
 setDescription("Click on this")
 setIcon(new ThemeResource("icons/ok.png"))
}
4
répondu Guillaume Belrose 2011-07-12 12:49:28
la source

excluant les membres de import déclarations

supposons que vous voulez utiliser une Logger qui contient une println et une printerr méthode, mais vous voulez seulement utiliser celle pour les messages d'erreur, et garder le bon vieux Predef.println pour la sortie standard. Vous pourriez faire ceci:

val logger = new Logger(...)
import logger.printerr

mais si logger contient aussi douze autres méthodes que vous voudriez importer et utiliser, il devient gênant de les énumérer. Vous pourriez plutôt essayer:

import logger.{println => donotuseprintlnt, _}

mais cela" pollue " toujours la liste des membres importés. Entrez le Joker über-powerful:

import logger.{println => _, _}

et cela fera juste la bonne chose ™.

3
répondu Philippe 2011-09-26 20:31:28
la source

require méthode (définie dans Predef ) qui vous permet de définir des contraintes de fonction supplémentaires qui seraient vérifiées pendant l'exécution. Imaginez que vous développer encore un autre client twitter et vous devez limiter tweet longueur jusqu'à 140 symboles. De plus, vous ne pouvez pas poster de tweet vide.

def post(tweet: String) = {
  require(tweet.length < 140 && tweet.length > 0) 
  println(tweet)
 }

appelle maintenant post avec l'argument de longueur inappropriée causera une exception:

scala> post("that's ok")
that's ok

scala> post("")
java.lang.IllegalArgumentException: requirement failed
    at scala.Predef$.require(Predef.scala:145)
    at .post(<console>:8)

scala> post("way to looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong tweet") 
java.lang.IllegalArgumentException: requirement failed
    at scala.Predef$.require(Predef.scala:145)
    at .post(<console>:8)

Vous pouvez écrire plusieurs

def post(tweet: String) = {
  require(tweet.length > 0, "too short message")
  require(tweet.length < 140, "too long message")
  println(tweet)
}

Maintenant, les exceptions sont verbose:

scala> post("")
java.lang.IllegalArgumentException: requirement failed: too short message
    at scala.Predef$.require(Predef.scala:157)
    at .post(<console>:8)

un autre exemple est ici .


Bonus

Vous pouvez effectuer une action à chaque fois que l'exigence d'échec:

scala> var errorcount = 0
errorcount: Int = 0

def post(tweet: String) = {
  require(tweet.length > 0, {errorcount+=1})
  println(tweet)
  }

scala> errorcount
res14: Int = 0

scala> post("")
java.lang.IllegalArgumentException: requirement failed: ()
    at scala.Predef$.require(Predef.scala:157)
    at .post(<console>:9)
...

scala> errorcount
res16: Int = 1
2
répondu om-nom-nom 2017-05-23 15:25:20
la source

Caractéristiques Avec abstract override méthodes sont une caractéristique dans Scala qui n'est pas aussi largement annoncé que beaucoup d'autres. L'intention des méthodes avec les abstract override modificateur est de faire quelques opérations et de déléguer l'appel super . Ensuite, ces caractéristiques doivent être mélangées avec des implémentations concrètes de leurs méthodes abstract override .

trait A {
  def a(s : String) : String
}

trait TimingA extends A {
  abstract override def a(s : String) = {
    val start = System.currentTimeMillis
    val result = super.a(s)
    val dur = System.currentTimeMillis-start
    println("Executed a in %s ms".format(dur))
    result
  }
}

trait ParameterPrintingA extends A {
  abstract override def a(s : String) = {
    println("Called a with s=%s".format(s))
    super.a(s)
  }
}

trait ImplementingA extends A {
  def a(s: String) = s.reverse
}

scala> val a = new ImplementingA with TimingA with ParameterPrintingA

scala> a.a("a lotta as")
Called a with s=a lotta as
Executed a in 0 ms
res4: String = sa attol a

alors que mon exemple n'est vraiment pas beaucoup plus qu'un pauvre mans AOP, j'ai utilisé ces Stackable Traits beaucoup à mon goût pour construire des instances d'interprétation Scala avec des importations prédéfinies, des fixations sur mesure et classpathes. Le Stackable Traits a permis de créer mon usine sur le modèle de new InterpreterFactory with JsonLibs with LuceneLibs et d'avoir ensuite des importations utiles et des varibles de scope pour les scripts utilisateurs.

1
répondu MxFr 2011-08-18 13:44:28
la source

Autres questions sur hidden-features scala