scalaはツンデレらしいが多少触っただけではさっぱりデレない。
scalaといえばplayframework。RailsにインスパイアされたEoDなフレームワークのはずだが詰まる詰まる。
主にはscalaの文法的なトコロに?と思ってしまうのだ。
scalaはrubyのようにDSLを書けることを意識しているためか、簡潔に書くための省略形が色々ある。
例えばジェネレーターで作られる以下のコード。
def index= Action {
Ok("Hello scala")
}
慣用句として見れば意味はわかる。シンプルだ。
だが、初学者で「とにかくイディオム覚えろ」だとモヤモヤする自分のようなタイプは「意味はわかるんだけど文法的にどういう意味なんだ?」と悩んでしまう。
def index =
はまぁ、普通のメソッド定義ということでOK。
よくわからなかったのは Action {...}の構文だ。
これは複数の要素が絡んでいる。
1. コンパニオンオブジェクト
まずActionのソースを見てみよう。
Actionはtraitである。
trait Action[A] extends EssentialAction {
そしてActionはコンパニオンオブジェクトである。
object Action extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[SimpleResult]) = block(request)
}
ActionBuilderもtraitなのでwithじゃねーの、と思うが一個の場合はextendsで良いらしい。
気持ち悪っ。
2. applyメソッド
ActionBuilderにapplyメソッドが定義されている。
final def apply(block: R[AnyContent] => Result): Action[AnyContent] = apply(BodyParsers.parse.anyContent)(block)
applyメソッドは特別扱いされていて
Action.apply(hoge)
は Action(hoge)
と書けるようになる。
3. ブロック
rubyと同じく {} で囲ってコードブロックを定義できる。
4. メソッド呼び出しのカッコは省略できる
だそうだ。
以上を総合してControllerのソースをもう一度見てみよう。
def index= Action {
Ok("Hello scala")
}
-
Action.apply({Ok("Hello scala")})
の省略形 - コンパニオンオブジェクトのapplyメソッドをcallしている
- 引数にブロックを渡している
ということになる。んー覚えること多すぎだな。。。
しかしまだ謎が残っていて、Okの存在だ。
これもコンパニオンオブジェクトのapplyなのはわかる。
これは Results.scalaに定義されている。
val Ok = new Status(OK)
それはいいんだけど気になるのは名前解決のところで、本来的には play.api.mvc.Results
のメンバーなのでResults.Ok(...)
と書かなきゃいけないのでは?? なんで Ok(...)
でいいのかからくりがわからないのであった。。。
↓
あー、Controller.scala見たら分かった。。ControllerがResultsをextendsしてるのか。
trait Controller extends Results with BodyParsers with HttpProtocol with Status with HeaderNames with ContentTypes with RequestExtractors with Rendering {