2014-12-21 11 views
5

Mi è stato detto che Scala offre la possibilità di modellare il flusso di controllo UNTIL, REPEAT.Perché il codice per modellare UNTIL/REPEAT richiede una nuova parola chiave?

Mentre studia la possibilità, ho trovato il codice:

// ref: https://gist.github.com/metasim/7503601 
def REPEAT(body: => Unit) = new { 
    def UNTIL(condition: => Boolean): Unit = { 
    body 
    if (condition)() 
    else UNTIL(condition) 
    } 
} 

// test code 
REPEAT { 
    x = x + 1 
} UNTIL (x > 3) 

Perché la parola chiave new in REPEAT funzione necessaria?

+0

Perché 'UNTIL' è un metodo, non un nome di una funzione (nger). –

+0

Quindi, 'new {}' crea un oggetto? come so, il metodo dovrebbe essere in un oggetto – 1ambda

risposta

3

new { def ...} costrutto crea un nuovo oggetto anonimo con structural typeAnyRef{def ...}:

scala> val aa = new { def kk = "bb" } 
aa: AnyRef{def kk: String} 

Il tuo metodo UNTIL è accessibile a causa della caratteristica chiamata "l'accesso riflettente di membro di tipo strutturale", e si dovrebbe anche avere un import scala.language.reflectiveCalls, almeno a Scala 2.11.2 a seguito di SIP 18: Modularizing Language Features:

scala> aa.kk 
<console>:9: warning: reflective access of structural type member method kk should be enabled 
by making the implicit value scala.language.reflectiveCalls visible. 
This can be achieved by adding the import clause 'import scala.language.reflectiveCalls' 
or by setting the compiler option -language:reflectiveCalls. 
See the Scala docs for value scala.language.reflectiveCalls for a discussion 
why the feature should be explicitly enabled. 
       aa.kk 
       ^
res0: String = bb 

Nota, che è un po 'più lento che definire class Repeatable {def UNTIL = ...}, perché (per JVM) la funzione REPEAT restituisce Object (AnyRef) e non è presente alcun tipo da trasmettere, quindi Scala invoca UNTIL utilizzando la reflection. Inoltre, non ha introdotto alcuna classe sintetica perché il tipo strutturale può corrispondere a qualsiasi classe esistente (qualsiasi altra classe con il metodo UNTIL appropriato).

+0

Grazie! Piuttosto profondo di quanto mi aspettassi. In sintesi, l'oggetto anonimo (AnyRef) ha l'aspetto di un oggetto anonimo (?). Non richiede classe, solo bisogno di implementazione. Ma ho ancora una domanda. Anche se non importassi ReflectiveCalls, il mio codice funziona. Solo l'interprete di scala richiede l'importazione di quel pacchetto? – 1ambda

+1

Yrw. l'oggetto stesso ha una classe (tipo formale) AnyRef, la digitazione anatra gli consente di avere un tipo reale con firma appropriata e di chiamarne i metodi per riflessione. Il tuo codice funziona, ma ricevi comunque questo avviso (il testo completo è disponibile con "scala-funzionalità") – dk14

Problemi correlati