2011年4月19日火曜日

C#のusing構文をScalaで

や、もちろんVB.NETのUsing構文でもいいんだけどね。

やっぱりJava触った後にC#とか触るとusing構文素敵だよね。
Scalaにはないのかにゃー?というとそういう構文はありません。
だがしかし!それっぽい構文を作ることはできるぞー、ということで作ってみよう。

まずはusing関数の定義

   1: def using[A <: {def close()}, B](r: A)(f: A => B) = {
   2:   try {
   3:      f(r)
   4:   } finally {
   5:      r.close
   6:   }
   7: }

ジェネリクス、カリー化、Structual type、高階関数辺り。
using関数はclose()メソッドを持つ何らかのオブジェクトと、A型(つまりcloseメソッドを持つ何らかの型)を受け取ってB型の値を返す関数、を受け取ってB型の結果を返す関数になります。
処理はいたって普通で、受け取った関数fを呼び出して、finallyでcloseするだけ。


んで、これを使うコード



   1: import java.sql.{Array => _, _}
   2:  
   3: object Main {
   4:  
   5:   def main(args: Array[String]) {
   6:     Class.forName("com.mysql.jdbc.Driver")
   7:  
   8:     val list =
   9:     using(DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "")){ conn =>
  10:       using(conn.prepareStatement("SELECT * FROM test")){ stmt =>
  11:         val rs = stmt.executeQuery
  12:         val list = scala.collection.mutable.ListBuffer[String]()
  13:  
  14:         while (rs.next) {
  15:           list += rs.getString("name")
  16:         }
  17:  
  18:         list.toList
  19:       }
  20:     }
  21:  
  22:     list.foreach(println)
  23:   }
  24: }

最初のimportはjava.sql.Arrayは除外してインポートする。
そうしないと普通のArrayとバッティングしてエラーになる。


あとは普通にusingを使ってやる、と。上のコードはMySQLに接続するコードですけど、深い意味はありません。
C#と違って構文ではなくて関数として作ったので、using全体の戻り値を変数に代入することもできます。


あれ?そういえばScalaって代入って言葉使っていいんだっけ?
変数をusing関数の戻り値に束縛することができる、って言ったほうが正確?

0 件のコメント:

コメントを投稿