¿Cuáles son todas las instancias de azúcar sintáctico en Scala?
syntactic-sugar (6)
Clases especiales: Tuplas y símbolos
Como menciona Rahul G , las tuplas y los símbolos tienen una sintaxis ligeramente especial.
- Símbolos: la sintaxis
''xes la abreviatura deSymbol("x") - Tuplas:
(p1,p2,..,pn)es la abreviatura de una clase de casoTuplen[T1,T2,..,Tn](p1,p2,..,pn)
Por ejemplo, los siguientes dos son equivalentes.
val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
¿Cuáles son todas las instancias de azúcar sintáctico en Scala?
Son difíciles de buscar ya que la mayoría / todos ellos son puramente símbolos y, por lo tanto, difíciles de buscar sin conocer el nombre del concepto.
QUE HACER:
- Conversiones implícitas
-
_sintaxis para funciones anónimas - Otras cosas que olvido
Extractores:
Hay dos métodos usados para extractores, unapply y unapplySeq . Estos se utilizan en asignaciones de variables múltiples y coincidencia de patrones.
El primer caso de uso es cuando una aplicación toma el objeto con el que se supone que debe coincidir y devuelve un
Booleansegún si coincide o no, por ejemplo,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))
Honestamente, realmente no entiendo el propósito de la sintaxis anterior, ya que se puede hacer casi igual de fácil simplemente colocando el código en las declaraciones de case . Por supuesto, si tiene un mejor ejemplo, deje un comentario a continuación
El caso general en el que
unapplyseunapplytoma un número fijo de parámetros y devuelve unaOption[T]para un solo parámetro o unaOption[(p1,p2,...)]para múltiples, es decir, una Tupla con los valores coincidentes, para ejemplo, continuando desde el código anterior: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?") }
Nota: Las clases Case hacen todas esas definiciones de apply / unapply para usted (así como para otras cosas) así que úselas siempre que sea posible para ahorrar tiempo y reducir el código.
-
unapplySeq. Esto funciona de manera similar aunapplycomo arriba, excepto que debe devolver unaOptionde algún tipo de secuencia.
Como un ejemplo rápido,
scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
Lo esencial:
-
abes equivalente aab -
abces equivalente aab(c), excepto cuandobtermina en:En ese caso,abces equivalente acb(a) a(b)es equivalente aa.apply(b)Esta es la razón por la cual las siguientes definiciones para funciones anónimas son idénticas: val square1 = (x: Int) => x x val square2 = new Function1 [Int, Int] {def aplicar (x: Int) = x x}Al llamar a
square1(y), en realidad está llamando asquare1.apply(y)quesquare1debe tener como lo especifica el rasgo deFunction1(oFunction2, etc ...)a(b) = ces equivalente aa.update(b,c)Del mismo modo,a(b,c) = des equivalente aa.update(b,c,d)y así sucesivamente.ab = ces equivalente aa.b_=(c). Cuando creas unval/varxen una clase / objeto, Scala crea los métodosxyx_=para ti. Puede definirlos usted mismo, pero si definey_=debe definiryo no se compilará, por ejemplo,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-acorrespondea.unary_-Dela.unary_-modo para+a,~ay!aa <operator>= b, donde<operator>es un conjunto de caracteres especiales, es equivalente aa = a <operator> bsolo siano tiene el método<operator>=, por ejemplo,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
Además de la respuesta de Jaxkson:
-
type F[A,B]se puede utilizar comoAFB.
Por ejemplo:
type ->[A,B] = (A,B)
def foo(f: String -> String)
- Usar
=> typeen una definición de método hace que el compilador ajuste las expresiones dentro de la llamada al método en un thunk de función.
Por ejemplo
def until(cond: => Boolean)(body: => Unit) = while(!cond) body
var a = 0
until (a > 5) {a += 1}
El contexto limita el azúcar en implicit parámetros implicit , por ejemplo, considera una función que aprovecha la clase de tipo Monoid :
def suml[T: Monoid](xs: List[T]) = {
val T = implicitly[Monoid[T]]
xs.foldLeft(T.mzero)(T.mplus)
}
donde la parte : Monoid es un contexto vinculado, se traduce a:
def suml[T](xs: List[T])(implicit evidence$1: Monoid[T]]) = {
...
}
por lo tanto, las siguientes compilaciones también:
def suml[T: Monoid](xs: List[T]) = {
val T = evidence$1
...
}
Funciones anónimas:
_ + _ es la abreviatura de (a, b) => a + b