Elenco delle funzioni “magiche” di Scala

Dove posso trovare una lista delle funzioni “magiche” di Scala, come apply , unapply , update , += , ecc.?

Per funzioni magiche intendo funzioni che sono usate da alcuni tipi di zucchero sintattico del compilatore, per esempio

 o.update(x,y)  o(x) = y 

Ho cercato su google una combinazione di scala magic e sinonimi di functions , ma non ho trovato nulla.

Non mi interessa l’ uso delle funzioni magiche nella libreria standard, ma in quali funzioni magiche esistono.

Per quanto ne so:

Getter / setter correlati:

 apply update identifier_= 

Pattern matching:

 unapply unapplySeq 

Per-comprensioni:

 map flatMap filter withFilter foreach 

Operatori prefissati:

 unary_+ unary_- unary_! unary_~ 

Oltre a ciò, qualsiasi implicito da A a B. Scala converte anche A = B in A = A B , se l’operatore precedente non è definito, “op” non è alfanumerico, e = non è != , == , <= or >= .

E non credo che ci sia un singolo posto in cui sono elencati tutti gli zuccheri sintattici di Scala.

Oltre ad update e apply , ci sono anche un numero di operatori unari che (credo) si qualificano come magici:

  • unary_+
  • unary_-
  • unary_!
  • unary_~

Aggiungete a ciò gli operatori regolari di infissi / suffissi (che possono essere quasi tutti) e avrete il pacchetto completo.

Dovresti davvero dare un’occhiata alle Specifiche della lingua di Scala. È l’unica fonte autorevole su questa roba. Non è difficile da leggere (a patto che tu stia bene con le grammatiche context-free), e facilmente ricercabile. L’unica cosa che non specifica bene è il supporto XML.

Scusa se non risponde esattamente alla tua domanda, ma il mio momento WTF preferito finora è @ come operatore di assegnazione all’interno della corrispondenza del modello. Grazie alla copia morbida di “Programming in Scala” ho scoperto cosa era abbastanza veloce.

Usando @ possiamo associare qualsiasi parte di un modello a una variabile e, se la corrispondenza del modello ha esito positivo, la variabile acquisirà il valore del modello secondario. Ecco l’esempio di Programming in Scala (Sezione 15.2 – Binding variabile):

 expr match { case UnOp("abs", e @ UnOp("abs", _)) => e case _ => } 

Se l’intera corrispondenza del modello ha esito positivo, la parte corrispondente alla parte UnOp (“abs”, _) viene resa disponibile come variabile e.

Ed ecco cosa dice Programming Scala al riguardo.

Sono definiti nella specifica della lingua di Scala. Per quanto ne so, ci sono solo tre funzioni “magiche” come hai detto.

Scalas Getter e Setter possono anche riferirsi alla tua “magia”:

 scala> class Magic { | private var x :Int = _ | override def toString = "Magic(%d)".format(x) | def member = x | def member_=(m :Int){ x = m } | } defined class Magic scala> val m = new Magic m: Magic = Magic(0) scala> m.member res14: Int = 0 scala> m.member = 100 scala> m res15: Magic = Magic(100) scala> m.member += 99 scala> m res17: Magic = Magic(199) 

Aggiungerò anche _* per la corrispondenza dei pattern su un numero arbitrario di parametri come

 case x: A(_*) 

E regola di associatività dell’operatore , dal libro di Odersky-Spoon-Venners:

L’associatività di un operatore in Scala è determinata dal suo ultimo carattere. Come menzionato su <...>, qualsiasi metodo che termina con un carattere ‘:’ viene invocato sul suo operando di destra, passando nell’operando di sinistra. I metodi che terminano in qualsiasi altro personaggio sono il contrario. Sono invocati sul loro operando di sinistra, passando nell’operando di destra. Quindi a * b produce a. * (B), ma a ::: b produce b.:::a).


Forse dovremmo menzionare anche la desaturazione sintattica delle espressioni che possono essere trovate qui


E (ovviamente!), Sintassi alternativa per coppie

 a -> b //converted to (a, b), where a and b are instances 

(come giustamente sottolineato, questa è solo una conversione implicita fatta attraverso una libreria, quindi probabilmente non è idonea, ma trovo che sia un comune rompicapo per i nuovi arrivati)


Vorrei aggiungere che esiste anche un tratto “magico” – scala.Dynamic :

Un tratto di marker che abilita le invocazioni dinamiche. Le istanze x di questo tratto consentono invocazioni di metodi x.meth(args) per nomi di meth arbitrari, elenchi di argomenti e liste di args , nonché campo accessi x.field per campo di nomi di field arbitrari.

Se una chiamata non è supportata nativamente da x (cioè se il controllo del tipo fallisce), viene riscritta in base alle seguenti regole:

 foo.method("blah") ~~> foo.applyDynamic("method")("blah") foo.method(x = "blah") ~~> foo.applyDynamicNamed("method")(("x", "blah")) foo.method(x = 1, 2) ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2)) foo.field ~~> foo.selectDynamic("field") foo.varia = 10 ~~> foo.updateDynamic("varia")(10) foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13) foo.arr(10) ~~> foo.applyDynamic("arr")(10) 

A partire da Scala 2.10, la definizione di sottoclassi dirette o indirette di questo tratto è ansible solo se la dynamic della funzione lingua è abilitata.

Quindi puoi fare cose del genere

 import scala.language.dynamics object Dyn extends Dynamic { def applyDynamic(name: String)(a1: Int, a2: String) { println("Invoked " + name + " on (" + a1 + "," + a2 + ")"); } } Dyn.foo(3, "x"); Dyn.bar(3, "y");