2010-06-18 20 views
17

Come esercizio, ho provato a creare una conversione implicita che accetta una funzione e produce un Runnable. In questo modo puoi chiamare i metodi Java che accettano gli oggetti Runnable e usarli come chiusure.Conversione implicita in Runnable?

La conversione implicita è abbastanza facile:

implicit def funToRunnable(fun : Unit) = new Runnable() { def run = fun } 

Tuttavia non so come chiamarlo. Come passi in una funzione no-arg che restituisce l'Unità, senza averla subito valutata? Ad esempio, mi piacerebbe quanto segue per stampare "12", ma invece stampa "21" perché print("2") viene valutato contemporaneamente.

var savedFun : Runnable = null 
    def save(r : Runnable) = { savedFun = r } 

    save(print("2")) 
    print("1") 
    savedFun.run() 

Come faccio a dire al compilatore di trattare print("2") come il corpo di una funzione, non è qualcosa che deve essere valutata in una volta? Alcune possibilità che ho provato, come

save(() => print("2")) 

o

save(=> print("2")) 

non sono la sintassi legale.

+0

si intende * "metodi Java chiamata che accettano runna bles e passare funzioni in loro come chiusure "*? perché i metodi che accettano altre funzioni non sono chiamati chiusure; le funzioni che accettano sono chiamate (a volte) chiusure. –

risposta

23

arg, ho appena risposto alla mia domanda. Ho implementato la conversione implicita in modo errato. La corretta applicazione è

implicit def funToRunnable(fun:() => Unit) = new Runnable() { def run() = fun() } 

e si chiama in questo modo:

save(() => print("2")) 

Questo produce "12"

+0

Ero sulla stessa traccia. Hai qualche idea sul perché "def run = run" non funziona? – OscarRyz

+2

'def run = run' sarà sempre una ricorsione infinita. Anche se esiste un 'run' definito in un ambito che racchiude, quello definito da questo' def' lo ombreggia, garantendo una chiamata ricorsiva diretta, incondizionata. –

+0

Intendevo "def run = fun" senza parents – OscarRyz

5

Interessante, in questo modo è possibile eseguire codice che riceve un Runnable e passarlo un chiusura.

See:

scala> new Thread(() => print("Hello")).start() 
<console>:5: error: overloaded method constructor Thread with alternatives (java.lang.ThreadGroup,java.lang.Runnable,java.lang.String,Long)java.lang.Thread <and> (java.lang.ThreadGroup,java.lang.Runnable,java.lang.String)java.lang.Thread <and> (java.lang.Runnable,java.lang.String)java.lang.Thread <and> (java.lang.ThreadGroup,java.lang.String)java.lang.Thread <and> (java.lang.String)ja... 
     new Thread(() => print("Hello")).start() 


scala> implicit def funcToRunnable(func :() => Unit) = new Runnable(){ def run() = func() } 
funcToRunnable: (() => Unit)java.lang.Object with java.lang.Runnable 

scala> def doRun(runnable: Runnable) = runnable.run 
doRun: (Runnable)Unit 

scala> doRun(() => print("Hola")) 
Hola 

scala> new Thread(()=>print("Hello")).start() 

scala> Hello 
12

Se si voleva vivere pericolosamente, è possibile convertire qualsiasi cosa per un eseguibile:

implicit def whateverToRunnable[F](f: => F) = new Runnable() { def run() { f } } 

scala> val t = new Thread(println("Hello")) 
t: java.lang.Thread = Thread[Thread-2,5,main] 

scala> t.start() 
Hello 

Oppure si potrebbe creare il proprio filo-creatore-e-starter:

def thread[F](f: => F) = (new Thread(new Runnable() { def run() { f } })).start 

scala> thread { println("Hi"); Thread.sleep(1000); println("Still here!") } 
Hi 

scala> Still here! 

Se si desidera restituire il thread, quindi

def thread[F](f: => F) = { 
    val t = new Thread(new Runnable() { def run() { f } }) 
    t.start() 
    t 
} 

Ma tutto ciò, anche se utile, è forse anche meno utile di scala.actors.Futures (testato solo su 2.8):

scala> import scala.actors.Futures 

scala> val x = Futures.future { Thread.sleep(10000); "Done!" } 
x: scala.actors.Future[java.lang.String] = <function0> 

scala> x.isSet 
res0: Boolean = false 

scala> x.isSet 
res1: Boolean = false 

scala> x() // Waits until the result is ready.... 
res2: java.lang.String = Done! 
0

Un altro modo per eseguire del codice in un thread diverso:

scala.actors.Actor.actor { ...doSomething()... } 
+0

Runnable non è solo utilizzato per eseguire roba in una nuova discussione. Ad esempio, nello sviluppo della GUI viene utilizzato per eseguire roba sul thread dell'interfaccia utente speciale. – Martin

4

In realtà, si può fare ancora più bello con l'argomento chiamata per nome:

implicit def runnable(f: => Unit): Runnable = new Runnable() { def run() = f } 

Uso:

import concurrent.ExecutionContext.Implicits.global._ 
execute(print("hello")) 
Problemi correlati