Каковы все случаи синтаксического сахара в Scala? - PullRequest
61 голосов
/ 18 апреля 2010

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

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

ТОДО:

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

Ответы [ 6 ]

57 голосов
/ 18 апреля 2010

Основа:

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

    При вызове 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). Когда вы создаете val / var x в классе / объекте, Scala создает для вас методы x и x_=. Вы можете определить их самостоятельно, но если вы определите y_=, вы должны определить y, иначе он не будет компилироваться, например,

    scala> val b = new Object{ def set_=(a: Int) = println(a) }
    b: java.lang.Object{def set_=(Int): Unit} = $anon$1@17e4cec
    
    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} = $anon$1@95a253
    
    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
    
19 голосов
/ 19 апреля 2010

В дополнение к ответу Джексона:

  • type F[A,B] может использоваться как A F B.

Например:

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

Например

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

var a = 0
until (a > 5) {a += 1}
18 голосов
/ 20 апреля 2010

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

Как уже упоминалось Рахул 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)
14 голосов
/ 20 апреля 2010

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

Для экстракторов используются два метода: unapply и unapplySeq. Они используются в множественных присвоениях переменных и сопоставлении с образцом.

  • В первом случае использования unapply берет объект, которому он должен соответствовать, и возвращает 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?")
    }
    

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

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

В качестве быстрого примера,

scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
5 голосов
/ 23 сентября 2014

Контекст ограничивает десугар в 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
  ...
}
5 голосов
/ 05 октября 2013

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

_ + _ это сокращение от (a, b) => a + b

...