Каковы все экземпляры синтаксического сахара в Scala?
Их трудно искать, так как большинство/все они - просто символы и таким образом твердо искать, не зная название понятия.
TODO:
_
синтаксис для анонимных функций ab
эквивалентно ab
abc
эквивалентно ab (c )
, за исключением случаев, когда b
заканчивается на :
. В этом случае a b c
эквивалентно c.b (a)
a (b)
эквивалентно a.apply (b)
Вот почему следующие определения анонимных функций идентичны:
val square1 = (x: Int) => x x
val square2 = new Function1 [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 = новый объект {def set _ = (a: Int) = println (a)}
b: java.lang.Object {def set _ = (Int): Unit} = $ anon $ 1 @ 17e4cec {{1} }
scala> b.set = 5
: 6: error: value set не является членом java.lang.Object {def set _ = (Int): Unit} {{ 1}} 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 <оператор> = b
, где <оператор >
- некоторый набор специальных символов, эквивалентен a = a <оператор> b
, только , если a
не имеет <оператор> = Метод
, например,
class test (val x: Int) {
def %% (y: Int) = new test (x * y)
} {{ 1}}
var a = new test (10)
ax // 10
a %% = 5 // Эквивалентно a = a %% 5
топор // 50
Как упоминал Рахул Дж. , кортежи и символы имеют несколько особый синтаксис.
'x
является сокращением от Symbol ("x")
(p1, p2, .., pn)
коротким для класса случая Tuplen [T1, T2, .., Tn] (p1, p2, .., pn)
Например, следующие два эквивалентны.
val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
Для экстракторов используются два метода: unapply
и unapplySeq
. Они используются при назначении нескольких переменных и сопоставлении с образцом.
Первый вариант использования - unapply берет объект, которому он должен соответствовать, и возвращает логическое значение
в зависимости от того, соответствует ли оно, например,
trait Gender
trait Male расширяет Gender
trait Female extends Gender
объект Male расширяет Male
объект Female расширяет женский
класс Person (val g: Gender, val age: Int) {{ 1}}
объект для взрослых {
def unapply (p: Person) = p.age> = 18
}
def check (p : Person) = p match {
case Adult () => println ("Взрослый")
case _ => println ("Ребенок")
} {{1 }}
// Напечатает: Взрослый, поскольку Adult.unapply возвращает true.
check (new Person (Female, 18))
// Напечатает : Ребенок в случае _.
check (new Person (Male, 17))
Честно говоря, я не совсем понимаю цель приведенного выше синтаксиса, поскольку это можно сделать почти так же легко, просто поместив код в операторы case
. Конечно, если у вас есть лучший пример, оставьте комментарий ниже.
Общий случай, когда unapply
принимает некоторое фиксированное количество параметров и возвращает либо Option [T]
для один параметр или Опция [(p1, p2, ...)]
для нескольких, то есть кортежа с совпадающими значениями, например, продолжением из приведенного выше кода:
объект Person {
def apply (g: Gender, age: Int) = new Person (g, age)
def unapply (p: Person) = if (p.age <0) None else Some ((pg, p.age))
}
{ {1}} // Использование Person.apply, как описано в разделе "Основные сведения"
val alice = Person (Female, 30)
val bob = Person (Male, 25)
{ {1}} // Это вызывает Person.unapply (alice), который возвращает Some ((Female, 30)).
// alice_gender назначается Female, а alice_age 30.
val Person (alice_gender) , alice_age) = alice
bob match {
// Вызывает Person.unapply (bob), но видит, что g - Male, поэтому совпадения нет.
case Person (Female, _) => println ("Hello ma'am")
// Вызывает Person.unapply (bob) и назначает age = bob.age, но не проходит
// оператор 'if', поэтому он здесь тоже не соответствует.
case Person (Male, age) if age <18 => println ("Hey dude")
// Итак Боб попадает сюда
case _ => println ("Здравствуйте, сэр")
}
Person (Male, -1) match {
//Person.unapply(Person.apply(Male,-1)) возвращает None, потому что p .age <0.
// Следовательно, этот случай не будет совпадать.
case Person (_, _) => println ("Hello person")
// Таким образом, он падает сюда.
case _ => println ("Вы человек?")
}
Примечание: Классы случаев выполняют все эти применить
/ отменить
определения для вас (а также другие вещи), поэтому используйте их, когда это возможно, чтобы сэкономить время и сократить объем кода.
unapplySeq
. Это работает аналогично unapply
, как указано выше, за исключением того, что он должен возвращать Option
некоторой последовательности.В качестве быстрого примера:
scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
В дополнение к ответу Джексона:
тип 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}