Неявное преобразование в Runnable?
В качестве упражнения я попытался создать неявное преобразование, которое примет функцию и создаст Runnable
. Таким образом, вы можете вызывать методы Java, которые принимают объекты Runnable
и используют их как закрытие.
Неявное преобразование достаточно просто:
implicit def funToRunnable(fun : Unit) = new Runnable() { def run = fun }
Однако я не знаю, как это назвать. Как вы передаете функцию no-arg, которая возвращает 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"))
не являются юридическим синтаксисом.
Ответы
Ответ 1
arg, просто ответил на мой собственный вопрос. Я неправильно применил неявное преобразование. Правильная реализация -
implicit def funToRunnable(fun: () => Unit) = new Runnable() { def run() = fun() }
и вы вызываете это следующим образом:
save(() => print("2"))
Это дает "12"
Ответ 2
Если вы хотите жить опасно, вы можете преобразовать что угодно в runnable:
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()... }