2010-06-18 169 views
17

作爲練習,我嘗試創建一個隱式轉換,它將接受函數並生成Runnable。這樣,您可以調用接受Runnable對象的Java方法,並像封閉一樣使用它們。隱式轉換爲Runnable?

的隱式轉換是很容易的:

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

但是我不知道該怎麼稱呼它。你如何傳遞一個返回Unit的無參數函數,而不需要一次性評估它?例如,我想要以下內容打印「12」,但是打印「21」,因爲print("2")一次被評估。

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

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

我如何告訴編譯器把print("2")的功能,不是身體立刻進行評估?一些可能性我想,如

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

save(=> print("2")) 

是不合法的語法。

+0

您的意思是*「調用接受Runna的java方法將功能塞進並傳遞給它們就像關閉「*?因爲接受其他函數的方法不被稱爲閉包;他們接受的功能被稱爲(有時)閉包。 – 2014-03-31 02:38:35

回答

23

arg,只是回答了我自己的問題。我錯誤地實現了隱式轉換。正確的實現是

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

,你這樣稱呼它:

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

這就產生了「12」

+0

我在同一條軌道上。你有什麼想法,爲什麼「運行=運行」不起作用? – OscarRyz 2010-06-18 23:49:41

+2

'def run = run'將永遠是一個無限遞歸。即使在封閉範圍中定義了一個'run',由這個'def'定義的'將會對它進行遮蔽,保證直接的,無條件的遞歸調用。 – 2010-06-19 01:27:53

+0

我的意思是'def run = fun'沒有parens – OscarRyz 2010-06-20 05:00:07

5

有趣的是,這種方式可以執行該接收Runnable代碼,並傳遞給它一個關閉。

參見:

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

如果你想驚險的生活,你可以什麼轉換爲可運行:

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 

或者你可以創建自己的線程創建者和首發:

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! 

如果你想返回線程,那麼

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

但是,所有這些雖然有用,但可能比scala.actors.Futures更有用(僅在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

另一種方法在不同的線程中運行一些代碼:

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

Runnable不僅用於在新線程中運行內容。例如在GUI開發中,它被用來在特殊的UI線程上運行東西。 – Martin 2012-05-24 09:09:44

4

其實,你可以與呼叫按姓名參數做到這一點甚至更好:

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

用法:

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