2010-04-18 1 views
61

Что все примеры синтаксического сахара в Scala?Каковы все случаи синтаксического сахара в Scala?

Их трудно найти, поскольку большинство/все они являются чисто символами и поэтому их трудно найти, не зная названия концепции.

TODO:

  • Неявные преобразования
  • _ синтаксис для анонимных функций
  • Другие вещи я забываю
+1

Больше TODO: кортежи, символы, XML-литералы. – missingfaktor

+0

Я не думаю, что XML подходит, потому что его не по-настоящему сахара в смысле сокращения чего-то еще. Однако я согласен с кортежами и символами. –

+2

Если вы видели, что код выполнен для создания экземпляров XML DOM, соответствующих XML-литералам, я думаю, вы должны согласиться с тем, что литералы являются аббревиатурой! –

ответ

55

Основы:

  • a b эквивалентно a.b
  • a b c эквивалентен a.b(c), за исключением случаев, когда b заканчивается на :. В этом случае a b c эквивалентно c.b(a)
  • a(b) эквивалентен a.apply(b) Поэтому следующие определения для анонимной функции идентичны: вал Square1 = (х: Int) => х х вала square2 = новые Function1 [Int, Int] { защиту применить (х: Int) = х х }

    При вызове square1(y), вы на самом деле вызова square1.apply(y) которые square1 должны быть, как указано в Function1 признака (или Function2, и т.д. ...)

  • a(b) = c эквивалентно a.update(b,c) Аналогично, a(b,c) = d эквивалентно a.update(b,c,d) и так далее.

  • a.b = c равнозначно a.b_=(c). Когда вы создаете /varx в классе/объекте, Scala создает для вас методы x и x_=.Вы можете определить это самостоятельно, но если вы определяете y_= вы должны определить y или он не компилируется, например,

    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 соответствует a.unary_- Аналогично для +a, ~a и !a

  • a <operator>= b, где <operator> - это набор специальных символов, эквивалентен a = a <operator> bтолько если a не имеет метод <operator>=, например,

    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

, так что если 'foo (bar)' эквивалентно 'foo.apply (bar)' then 'foo.apply (bar)' должно быть эквивалентно 'foo.apply.apply (bar)' и т. Д. –

+0

Как приятно искать «x y» и обнаруживать, что это просто «x.y». Как это делает вещи более удобными, это то, чего я действительно не понимаю. Спасибо за вашу помощь. – Dacav

+0

Благодарим вас за предупреждение о том, что поле 'y' необходимо для поля' y_ = ' – radke

19

В дополнение к ответу Jaxkson в:

  • type F[A,B] могут быть использованы в качестве A F B.

Например:

type ->[A,B] = (A,B) 
def foo(f: String -> String) 
  • Использование => type в определении метода делает компилятор обруча выражения внутри вызова метода в функции стуком.

Например

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

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

. Я действительно не знал об этом первом синтаксисе, интересном. Вот почему нам нужна сводная страница, подобная этой. –

+0

Можете ли вы привести пример для первого syntaxt?Это будет отличная помощь. – asyncwait

14

Экстракторы:

Есть два метода, используемые для экстракторов, unapply и unapplySeq. Они используются в нескольких назначениях переменных и сопоставлении шаблонов.

  • Первый случай использования, где исключить его принимает объект он должен соответствовать и возвращает Boolean в зависимости от того или не соответствует его, например,

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

Честно говоря, я на самом деле не получают цели вышеупомянутого синтаксиса, так как это можно сделать почти так же просто, просто поместив код в операторы case. Конечно, если у вас есть лучший пример, оставьте комментарий ниже

  • Общий случаем, когда unapply занимает некоторое фиксированное число параметров и возвращает либо Option[T] для одного параметра или Option[(p1,p2,...)] для нескольких, т.е. Кортеж с соответствием значений, например, продолжив из кода выше:

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

Примечание:Case classes делать все те apply/unapply (как и другие материалы), поэтому используйте их, когда это возможно, чтобы сэкономить время и уменьшить код.

  • unapplySeq. Это работает аналогично unapply, как указано выше, за исключением того, что он должен возвращать Option какой-либо последовательности.

Как простой пример,

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

Специальные классы: кортежи и символы

Как отметил Rahul G, кортежи и символы получить немного специальный синтаксис.

  • Символы: синтаксис 'x короток для Symbol("x")
  • кортежей: (p1,p2,..,pn) коротка для случая класса Tuplen[T1,T2,..,Tn](p1,p2,..,pn)

Например, следующие два эквивалентны.

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

Это не уникально для кортежей и символов: строки, целые числа, longs, double, floats, characters, boolean, функции, XML и 'null' также имеют специальный литерал-синтаксис. Фактически, я бы спорил о том, являются ли литералы «синтаксическим сахаром» вообще. Синтаксический сахар - это чисто локальное преобразование кода. На что превращаются литералы? –

4

Анонимные функции:

_ + _ короток для (a, b) => a + b

3

Контекст границ desugar в implicit параметров, например Рассмотрим функцию, которая использует класс Monoid типа:

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

где : Monoid часть контекста связана, переводится на:

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

поэтому следующие компилирует тоже:

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