ScalaではC#のusingみたいのを簡単に作れるよ、というのはよくある話ですが、ScalazのResourcesトレイトで定義されているwithResourceメソッドで同じようなことができます。以下はjava.io.InputStreamから文字列として読み込む場合の例です。
import scalaz._ import Scalaz._ import java.io._ val result = withResource[InputStream, String]( new FileInputStream("hoge.txt"), { in: InputStream => val array = new Array[Byte](in.available) in.read(array) new String(array, "UTF-8") })
デフォルトでは引数で渡している関数の処理で例外が発生した場合はクローズ後に例外がスローされ、クローズ処理で例外が発生した場合は握りつぶされますが、例外発生時に呼び出される関数を指定することもできます。以下のコードではわかりやすいように例外発生時に呼び出される関数を名前付きパラメータで指定しています。
val result = withResource[InputStream, String]( new FileInputStream("hoge.txt"), { in: InputStream => ... }, whenComputing = { t: Trhowable => t.toString }, whenClosing = { t: Trhowable => println(t.toString) })
処理本体の関数での例外発生時はwhenComputingで指定した関数の戻り値がwithResourceメソッドの戻り値になり、クローズ処理で例外が発生した場合はwhenClosingで指定した関数が呼び出された後、本体の関数の戻り値が返されます。
withResourceメソッドは以下の型をリソースとして扱うことができます。
実際には上記の型はResource[T]に暗黙的に変換されてwithResourceメソッドで処理されているので、型変換を行う関数を追加することで対応する型を増やせるのかな…と思ったのですが、Resourceトレイトはsealされているのでそういうことはできませんでした。なんかいまいちですねー。
Scala IO(というかARMだっけ?)の同様の機能ではcloseメソッドもしくはdisposeメソッドが定義されている型であればすべてリソースとして扱うことができたり、複数のリソースを同時に扱えるようになっていたりして便利です。Scalazもせめて拡張できるようになっていればいいんですけどねぇ…。