scala syntactic-sugar

¿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 ''x es la abreviatura de Symbol("x")
  • Tuplas: (p1,p2,..,pn) es la abreviatura de una clase de caso Tuplen[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 Boolean segú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 unapply se unapply toma un número fijo de parámetros y devuelve una Option[T] para un solo parámetro o una Option[(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 a unapply como arriba, excepto que debe devolver una Option de 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:

  • ab es equivalente a ab
  • abc es equivalente a ab(c) , excepto cuando b termina en : En ese caso, abc es equivalente a cb(a)
  • a(b) es equivalente a a.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 a square1.apply(y) que square1 debe tener como lo especifica el rasgo de Function1 (o Function2 , etc ...)

  • a(b) = c es equivalente a a.update(b,c) Del mismo modo, a(b,c) = d es equivalente a a.update(b,c,d) y así sucesivamente.

  • ab = c es equivalente a a.b_=(c) . Cuando creas un val / var x en una clase / objeto, Scala crea los métodos x y x_= para ti. Puede definirlos usted mismo, pero si define y_= debe definir y o 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

  • -a corresponde a.unary_- Del a.unary_- modo para +a , ~a y !a

  • a <operator>= b , donde <operator> es un conjunto de caracteres especiales, es equivalente a a = a <operator> b solo si a no 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 como AFB .

Por ejemplo:

type ->[A,B] = (A,B) def foo(f: String -> String)

  • Usar => type en 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