2010-04-18 6 views
61

Quelles sont toutes les instances de sucre syntaxique dans Scala?Quels sont tous les exemples de sucre syntaxique à Scala?

Ils sont difficiles à rechercher car la plupart/tous sont des symboles purs et sont donc difficiles à rechercher sans connaître le nom du concept.

TODO:

  • conversions implicites
  • syntaxe _ pour les fonctions anonymes
  • D'autres choses que je oublie
+1

Plus de TODOs: Tuples, Symboles, Littéraux XML. – missingfaktor

+0

Je ne pense pas que le XML s'adapte parce que ce n'est pas vraiment du sucre dans le sens de sténographie d'autre chose. Je suis d'accord sur les Tuples et les Symboles. –

+2

Si vous avez vu le code exécuté pour construire les instances DOM XML correspondant à un littéral XML, je pense que vous devez convenir que les littéraux sont une abréviation! –

Répondre

55

Principes de base:

  • a b est équivalent à 01.236.
  • a b c est équivalent à a.b(c), sauf lorsque b se termine par :. Dans ce cas, a b c équivaut à c.b(a)
  • a(b) est équivalent à a.apply(b) Voilà pourquoi les définitions suivantes pour une des fonctions anonymes sont identiques: val square1 = (x: Int) => x x val square2 = new fonction1 [Int, Int] { def applique (x: Int) = x x }

    Lorsque vous appelez square1(y), vous appelez en fait square1.apply(y) qui square1 doit avoir comme indiqué par le trait Function1 (ou Function2, etc. ...)

  • a(b) = c est équivalent à a.update(b,c) De même, a(b,c) = d est équivalent à a.update(b,c,d) et ainsi de suite.

  • a.b = c est équivalent à a.b_=(c). Lorsque vous créez un val/var dans une classe/objet, Scala crée les méthodes x et x_= pour vous.Vous pouvez définir vous-même ces, mais si vous définissez y_= vous devez définir y ou il ne compilera pas, par exemple,

    scala> val b = new Object{ def set_=(a: Int) = println(a) } 
    b: java.lang.Object{def set_=(Int): Unit} = [email protected] 
    
    scala> b.set = 5 
    <console>:6: error: value set is not a member of java.lang.Object{def set_=(Int): Unit} 
         b.set = 5 
         ^
    
    scala> val c = new Object{ def set = 0 ; def set_=(a:Int) = println(a) } 
    c: java.lang.Object{def set: Int; def set_=(Int): Unit} = [email protected] 
    
    scala> c.set = 5 
    5 
    
  • -a correspond à a.unary_- même pour +a, ~a et !a

  • a <operator>= b, où <operator> est un ensemble de caractères spéciaux, est équivalent à a = a <operator> bseulement si a n'a pas la méthode <operator>=, par exemple,

    class test(val x:Int) { 
        def %%(y: Int) = new test(x*y) 
    } 
    
    var a = new test(10) 
    a.x // 10 
    a %%= 5 //Equivalent to a = a %% 5 
    a.x // 50 
    
+0

donc si 'foo (bar)' est équivalent à 'foo.apply (bar)' alors 'foo.apply (bar)' devrait être équivalent à 'foo.apply.apply (bar)', et ainsi de suite. –

+0

Comme c'est agréable de chercher autour de 'x y' et de découvrir que c'est simplement comme' x.y'. Comment est-ce que cela rend les choses plus maniables, c'est quelque chose que je ne comprends pas vraiment. Merci de votre aide. – Dacav

+0

Merci pour l'avertissement qu'un champ 'y' est requis pour un champ' y_ = ' – radke

19

En plus de la réponse de Jaxkson:

  • type F[A,B] peut être utilisé comme A F B.

Par exemple:

type ->[A,B] = (A,B) 
def foo(f: String -> String) 
  • En utilisant => type dans une définition de méthode rend les expressions wrap du compilateur dans l'appel de méthode dans une thunk fonction.

Par exemple

def until(cond: => Boolean)(body: => Unit) = while(!cond) body 

var a = 0 
until (a > 5) {a += 1} 
+1

Je ne savais pas vraiment sur cette première syntaxe, intéressant. C'est pourquoi nous avons besoin d'une page consolidée comme celle-ci. –

+0

Pouvez-vous donner un exemple pour le premier syntaxt?Ce sera très utile – asyncwait

14

Extracteurs:

Il existe deux méthodes utilisées pour les essoreuses, unapply et unapplySeq. Ils sont utilisés dans plusieurs affectations de variables et correspondances de modèles.

  • Le premier cas d'utilisation est où unapply prend l'objet qu'il est censé correspondre et retourne un Boolean en fonction de si oui ou non elle correspond, par exemple,

    trait Gender 
    trait Male extends Gender 
    trait Female extends Gender 
    object Male extends Male 
    object Female extends Female 
    class Person(val g: Gender, val age: Int) 
    
    object Adult { 
        def unapply(p: Person) = p.age >= 18 
    } 
    
    def check(p: Person) = p match { 
        case Adult() => println("An Adult") 
        case _ => println("A Child") 
    } 
    
    //Will print: An Adult since Adult.unapply returns true. 
    check(new Person(Female, 18)) 
    
    //Will print: A Child as it falls through to the _ case. 
    check(new Person(Male, 17)) 
    

Honnêtement, je N'a pas vraiment le but de la syntaxe ci-dessus, car il peut être fait presque aussi simplement en mettant le code dans les instructions case. Bien sûr, si vous avez un meilleur exemple, laisser un commentaire ci-dessous

  • Le cas général où unapply prend un certain nombre d'actions fixe de paramètres et retourne soit un Option[T] pour un seul paramètre ou un Option[(p1,p2,...)] pour plusieurs, soit un tuple avec les valeurs reconnues, par exemple, continue à partir du code ci-dessus:

    object Person { 
        def apply(g: Gender, age: Int) = new Person(g, age) 
        def unapply(p: Person) = if(p.age < 0) None else Some((p.g, p.age)) 
    } 
    
    //Using Person.apply as described in the Basics section 
    val alice = Person(Female, 30) 
    val bob = Person(Male, 25) 
    
    //This calls Person.unapply(alice), which returns Some((Female, 30)). 
    //alice_gender is assigned Female and alice_age 30. 
    val Person(alice_gender, alice_age) = alice 
    
    bob match { 
        //Calls Person.unapply(bob), but sees that g is Male, so no match. 
        case Person(Female, _) => println("Hello ma'am") 
        //Calls Person.unapply(bob) and assigns age = bob.age, but it doesn't pass 
        //the 'if' statement, so it doesn't match here either. 
        case Person(Male, age) if age < 18 => println("Hey dude") 
        //So bob falls through to here 
        case _ => println("Hello Sir") 
    } 
    
    Person(Male,-1) match { 
        //Person.unapply(Person.apply(Male,-1)) returns None because p.age < 0. 
        //Therefore this case will not match. 
        case Person(_, _) => println("Hello person") 
        //Thus it falls through to here. 
        case _ => println("Are you Human?") 
    } 
    

note:Case classes font tous ceux apply/unapply définitions pour vous (ainsi que d'autres choses), utilisez-les dès que possible pour gagner du temps et réduire le code.

  • unapplySeq. Cela fonctionne de manière similaire à unapply comme ci-dessus, sauf qu'il doit retourner un Option d'une sorte de séquence.

Comme un exemple rapide,

scala> List.unapplySeq(List(1,2,3)) 
res2: Some[List[Int]] = Some(List(1, 2, 3)) 
18

Classes spéciales: Tuples et symboles

Comme mentionné par Rahul G, tuples et les symboles reçoivent une syntaxe légèrement spéciale.

  • Symboles: la syntaxe 'x est l'abréviation de Symbol("x")
  • Tuples: (p1,p2,..,pn) est courte pour une classe de cas Tuplen[T1,T2,..,Tn](p1,p2,..,pn)

Par exemple, les deux suivantes sont équivalentes.

val tuple1 = ("Hello",1) 
val tuple2 = Tuple2[String,Int]("Hello",1) 
+1

Ceci n'est pas unique aux tuples et aux symboles, cependant: les chaînes, entiers, longs, doubles, flottants, caractères, booléens, fonctions, XML et 'null' ont aussi une syntaxe littérale spéciale. En fait, je discuterais de la question de savoir si les littéraux sont ou non du «sucre syntaxique». Le sucre syntaxique est une transformation purement locale du code. À quoi les littéraux sont-ils transformés? –

4

fonctions Anonymous:

_ + _ est l'abréviation de (a, b) => a + b

3

bornes de contexte desugar en implicit paramètres, par exemple une fonction qui nous tire parti de la classe de type Monoid:

def suml[T: Monoid](xs: List[T]) = { 
    val T = implicitly[Monoid[T]] 
    xs.foldLeft(T.mzero)(T.mplus) 
} 

où la partie : Monoid est un contexte lié, est traduite à:

def suml[T](xs: List[T])(implicit evidence$1: Monoid[T]]) = { 
    ... 
} 

donc les compiles suivantes aussi:

def suml[T: Monoid](xs: List[T]) = { 
    val T = evidence$1 
    ... 
} 
Questions connexes