Task
前回のFutureに続き、今回はscalaz.concurrent.Taskを見てみよう。
Taskは、scalaz.concurrent.Future(以下Future)の例外処理を扱う版だ。(ソースコード)
class Task[+A](val get: Future[Throwable \/ A])
Futureは例外が起きてもスルーされるみたいだ。
scala> Future("a".toInt).start
res1: scalaz.concurrent.Future[Int] = Suspend(<function0>)
scala.concurrent.Future(以下scala.Future)も例外処理を扱うので、scala.Futureの代わりに使うならTaskだ。
使ってみよう
run: 同期実行。例外が飛ぶ。runAsyncで非同期。
scala> Task("a".toInt).run
java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
...
attemptRun: 同期実行し\/で取得できる。
scala> Task("a".toInt).attemptRun
res5: scalaz.\/[Throwable,Int] = -\/(java.lang.NumberFormatException: For input string: "a")
非同期にattemptRunする場合は、attemptしてrunAsync。
scala> Task("a".toInt).attempt.runAsync { case \/-(a) => println(s"success $a") case -\/(e) => println(e) }
success -\/(java.lang.NumberFormatException: For input string: "a")
handleWith: エラーハンドル。
scala> Task("a".toInt).handle { case e: Throwable => 0 }.run
res16: Int = 0
or: 失敗したら渡したTaskを返す。
scala> Task("a".toInt) or Task(1) attemptRun
res20: scalaz.\/[Throwable,Int] = \/-(1)
もちろんforも使えるので、順番に実行できる。
scala> for { a <- Task(1); b <- Task("b".toInt) } yield a + b
res21: scalaz.concurrent.Task[Int] = scalaz.concurrent.Task@758debda
scala> .attemptRun
res22: scalaz.\/[Throwable,Int] = -\/(java.lang.NumberFormatException: For input string: "b")
scala.Futureと違って都度forkしないので効率的なはず? というかそもそもcompleteしてから次の処理を実行するからforkする必要ないし、スタックレスなトランポリンは最適なのか。
まとめて結果を取得するものもある。この辺はFutureと同じ。
scala> Task.gatherUnordered { Task(1) :: Task(2) :: Task(3) :: Nil }.run
res33: List[Int] = List(1, 2, 3)
こけた場合
scala> Task.gatherUnordered { Task(1) :: Task("a".toInt) :: Task(3) :: Nil }.attemptRun
res35: scalaz.\/[Throwable,List[Int]] = -\/(java.lang.NumberFormatException: For input string: "a")
ほとんどの場合、Taskを使うことになるんじゃないだろうか。
細かいところまで見れてないが、今日はここまで。