Каковы все случаи синтаксического сахара в Scala?
Каковы все случаи синтаксического сахара в Scala?
Их трудно найти, поскольку большинство / все они являются чисто символами, и поэтому их трудно искать, не зная названия концепции.
СДЕЛАТЬ:
- Неявные преобразования
_
синтаксис для анонимных функций- Другие вещи, которые я забыл
6 ответов
Основы:
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) = 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
Специальные классы: кортежи и символы
Как упомянул missingfaktor., кортежи и символы получают немного особый синтаксис.
- Символы: синтаксис
'x
коротка дляSymbol("x")
- Кортеж:
(p1,p2,..,pn)
коротка для тематического классаTuplen[T1,T2,..,Tn](p1,p2,..,pn)
Например, следующие два являются эквивалентными.
val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
В дополнение к ответу Джексона:
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}
Экстракторы:
Есть два метода, используемых для экстракторов, 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?") }
Примечание: классы Case делают все это apply
/unapply
определения для вас (а также другие вещи), так что используйте их, когда это возможно, чтобы сэкономить время и сократить код.
unapplySeq
, Это работает аналогичноunapply
как указано выше, за исключением того, что он должен вернутьOption
какой-то последовательности.
В качестве быстрого примера,
scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
Контекст ограничивает десугар в 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
...
}