【问题标题】:Implicit conversion to Runnable?隐式转换为 Runnable?
【发布时间】:2011-03-05 15:49:21
【问题描述】:

作为练习,我尝试创建一个隐式转换,它可以接受一个函数并生成一个Runnable。这样您就可以调用接受Runnable 对象的Java 方法并像闭包一样使用它们。

隐式转换很简单:

    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"))

不是合法的语法。

【问题讨论】:

  • 你的意思是“调用接受Runnables的java方法并像闭包一样将函数传递给它们”?因为接受其他函数的方法不称为闭包;它们接受的函数称为(有时)闭包。

标签: scala runnable implicit-conversion


【解决方案1】:

arg,刚刚回答了我自己的问题。我错误地实现了隐式转换。正确的实现是

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

你这样称呼它:

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

这将产生“2”

【讨论】:

  • 我在同一条轨道上。你知道为什么def run = run 不起作用吗?
  • def run = run 将永远是一个无限递归。即使在封闭范围内定义了 run,由 def 定义的 def 也会隐藏它,从而保证直接、无条件的递归调用。
  • 我的意思是 def run = fun 没有括号
  • @Support 因为不带括号的 fun 只会创建一个返回传递函数的方法。要调用函数类型,您必须使用括号,否则您只是返回函数本身。
  • 是否应该产生 2 而不是 12?
【解决方案2】:

如果你想危险地生活,你可以将任何东西转换为可运行:

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!

【讨论】:

    【解决方案3】:

    有趣的是,这样您就可以执行接收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
    

    【讨论】:

      【解决方案4】:

      实际上,您可以使用按名称调用参数做得更好:

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

      用法:

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

      【讨论】:

        【解决方案5】:

        另一种在不同线程中运行代码的方法:

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

        【讨论】:

        • Runnable 不仅用于在新线程中运行东西。例如,在 GUI 开发中,它用于在特殊的 UI 线程上运行东西。
        猜你喜欢
        • 2015-03-16
        • 1970-01-01
        • 2010-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-23
        • 2010-12-12
        • 1970-01-01
        相关资源
        最近更新 更多