scalaのシグニチャを解読しよう。scalaで関数リテラルを継承!
class Handler(cfg: Config) extends (HttpRequest => Future[HttpResponse]) {
override def apply(request: HttpRequest): Future[HttpResponse] = {
...
}
}
ポイントは
関数リテラルを継承している
applyで実態を作っている
関数リテラルの復習です
() => Z //Takes 0 params and returns something of type Z
A => Z //Takes one param of type A and returns something of type Z
(A, B) => Z //Takes two params of type A and B and returns something of type
Z (A, B, C) => Z //...
上の関数リテラルは下記クラスのエイリアスに過ぎません
Function0[Z]
Function1[A, Z]
Function2[A, B, Z]
Function3[A, B, C, Z] //...
なので一つの引数を持つ関数を継承したクラスは以下のように二通りでかけます。
class IntToStringConverter extends Int => String {
def apply(i: Int): String = i.toString
}
//or, more explicitly:
class IntToStringConverter extends Function1[Int, String] {
def apply(i: Int): String = i.toString
}
applyメソッドは抽象関数でFunctionXでは実装されていませんので継承先でのapplyが実行されることになります
val c = new IntToStringConverter
val str = c(3) //is the same as c.apply(3)
println(str)
では以下のような例を見てみましょう
引数を一つ取って、それをindexとしてそのエレメントを返すリストの関数を作りたいと思います。
継承させてクラス形式で書いたものが下
case class Foo(x: Int)
val foos = List(Foo(3), Foo(1), Foo(9))
class X(foo: List[Foo]) extends (Int => Foo) {
def apply(idx: Int): Foo = { foo(idx) }
}
new X(foos)(2)
通常の関数で実現したのが下
def func1(idx: Int, foos: List[Foo]): Foo = foos(idx)
func1(2, foos)
メリットはパッと思いつかないのですが、
あえて言うなら
ただの関数ですがクラスという凝集性の高い部品が作りやすくメンテナンス性の高い
ということでしょうか。
ともかくScalaでは様々なむずい、とっつきにくシグニチャに遭遇しますが
未知なる敵との戦いと一緒で
楽しみながら
レベルを上げていきましょうー