Каковы все примеры синтаксического сахара в Scala?
Каковы все примеры синтаксического сахара в Scala?
Их трудно найти, так как большинство/все они являются чисто символами и поэтому их трудно найти, не зная названия понятия.
TODO:
- Неявные преобразования
-
_
синтаксис анонимных функций
- Другие вещи, которые я забываю
Ответы
Ответ 1
Основы:
-
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) = > xx val square2 = new Function1 [Int, Int] { def apply (x: Int) = xx }
При вызове 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} = [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
Ответ 2
В дополнение к Jaxkson ответ:
-
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}
Ответ 3
Специальные классы: кортежи и символы
Как упоминалось Rahul G, кортежи и символы получают немного специальный синтаксис.
- Символы: синтаксис
'x
не подходит для Symbol("x")
- Кортежи:
(p1,p2,..,pn)
является коротким для класса case Tuplen[T1,T2,..,Tn](p1,p2,..,pn)
Например, следующие два эквивалентны.
val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
Ответ 4
Экстракторы:
Для экстракторов используются два метода 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,...)]
для нескольких, т.е. Tuple с соответствующими значениями, например, продолжение из приведенного выше кода:
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
Анонимные функции:
_ + _
не подходит для (a, b) => a + b
Ответ 6
Контекст ограничивает десугар на параметры 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
...
}