ページ

2013-03-06

Play framework2.1でimplicitを使ってJsonを良い感じに扱う [Scala]


Play framework2.1でJsonを使った時のお話。

Playは2.1からJson周りがパワーアップしてまだ全容が理解できていません。
Play2.0のときはJsonはちゃんと使わなかったので、今回はちょっと調べてやってみました。

まずは下のようなモデルをJson(JsValue)に変換するとします。


このインスタンスをJsValueに変換するとき、最初は以下のように書いてました。


まずMapの中の要素が各々Json.toJsonでJsValueに変換されて、その後にMapそのものもJson.toJsonでJsValueに変換してって… わけわからんわー!

Json.toJsonってのが沢山出てきてブチ切れそうになりました。

よくよく調べてみると以下のように書くといい感じっぽいです。




implicitで始まってる所がモデルをJsValueに変換する方法の定義です。toJsonとか無くて良いですね。

JsValueに変換するときにJson.toJsonを呼ぶだけです。implicitと組み合わせることで、元々あるJson.toJsonを拡張するように使用できます(既存のコードに手を加えず)。

この辺がどうなっているのか少し詳しく説明します。


まずPlay2のJson.toJsonの定義は以下のようになっています。
def toJson[T](o: T)(implicit tjs: Writes[T]): JsValue = tjs.writes(o)

Scalaを読んだことがない人には非常に分かり難いですが、これはメソッド宣言です。

defはメソッドであることを示しtoJsonがメソッド名です。[T]はジェネリクスの型パラメータです。

(o: T)は1つ目の引数で、T型のオブジェクトoを引数に取ります。

(implicit tjs: Writes[T])は2つ目の引数で、Writes[T]型のオブジェクトを引数に取ります。Writes[T]型はT型をJsValueに変換する方法が定義されてる型です。

: JsValueはこのメソッドの戻り値の型がJsValueであることを示します。

=以降にメソッドの実際の処理で、この場合はtjs.writes(o)を実行しているだけです。

長くなりましたが、このメソッドがやっていることは、T型のoをtjsの定義に基づいてJsValueに変換しているだけです。

ここで、重要なのが2番目のimplicitで始まっている引数です。
これは暗黙の引数と言われるものです。

なんと、この関数(Json.toJson)を使用するときには暗黙の引数を指定しなくても、実行出来ます!!!(なにそれコワイ&先ほどのコードにも指定されていませんでしたよね?)

実は暗黙の引数の部分を渡さないと、コンパイラがエラーを出す前にソースコード中から適しているものを探して勝手に使ってくれます。適切なものが見つからない場合はエラーになるので、安全性は高いです。

この機能により、Json.toJsonに渡す型がなんであれ、JsValueに変換可能であれば使えるようになります。

新たに関数を作るよりも、既存の関数(Json.toJson)を拡張するような感じでコーディングすることが出来るのでコード自体にも統一感が出ていいと思います。


スゴイ!!

暗黙の引数!!





0 件のコメント:

コメントを投稿