このアイデアを思いついたときに、プロジェクト (Play Framework 2.4) で自分のスカラ コードをリファクタリングしようとしています。
(最小限の作業例を提供するために、いくつかのクラスを変更しました。たとえば、Result と Future[Result] をそれぞれ Int と Option[Int] に変更しました)
object ParFuncApply {
trait CanBeAuthenticatedRequest[A]
trait AuthenticatedRequest[A] extends CanBeAuthenticatedRequest[A]
trait UnauthenticatedRequest[A] extends CanBeAuthenticatedRequest[A]
private def fold[T](authenticated: (AuthenticatedRequest[_]) => T)
(unauthenticated: (UnauthenticatedRequest[_]) => T):
PartialFunction[CanBeAuthenticatedRequest[_], T] = {
case ar: AuthenticatedRequest[_] => authenticated(ar)
case ur: UnauthenticatedRequest[_] => unauthenticated(ur)
}
def apply(request: CanBeAuthenticatedRequest[_])
(authenticated: (AuthenticatedRequest[_]) => Int)
(unauthenticated: (UnauthenticatedRequest[_]) => Int): Int = {
fold(authenticated)(unauthenticated)(request)
}
def async(request: CanBeAuthenticatedRequest[_])
(authenticated: (AuthenticatedRequest[_]) => Option[Int])
(unauthenticated: (UnauthenticatedRequest[_]) => Option[Int]): Option[Int] = {
fold(authenticated)(unauthenticated)(request)
}
}
上記のコードはコンパイルされます。
それから私は: fold[T] パラメーター化された型を Int と Option[Int] に制限する必要があるので、以下を追加しました:
object ParFuncApply {
trait CanBeAuthenticatedRequest[A]
trait AuthenticatedRequest[A] extends CanBeAuthenticatedRequest[A]
trait UnauthenticatedRequest[A] extends CanBeAuthenticatedRequest[A]
sealed trait Helper[T]
object Helper {
implicit object FutureResultHelper extends Helper[Option[Int]]
implicit object ResultHelper extends Helper[Int]
}
private def fold[T: Helper](authenticated: (AuthenticatedRequest[_]) => T)
(unauthenticated: (UnauthenticatedRequest[_]) => T):
PartialFunction[CanBeAuthenticatedRequest[_], T] = {
case ar: AuthenticatedRequest[_] => authenticated(ar)
case ur: UnauthenticatedRequest[_] => unauthenticated(ur)
}
def apply(request: CanBeAuthenticatedRequest[_])
(authenticated: (AuthenticatedRequest[_]) => Int)
(unauthenticated: (UnauthenticatedRequest[_]) => Int): Int = {
fold(authenticated)(unauthenticated)(request)
}
def async(request: CanBeAuthenticatedRequest[_])
(authenticated: (AuthenticatedRequest[_]) => Option[Int])
(unauthenticated: (UnauthenticatedRequest[_]) => Option[Int]): Option[Int] = {
fold(authenticated)(unauthenticated)(request)
}
}
しかし、次のように変更すると、このコードはもはやコンパイルされません:
(apply() への明示的な呼び出しを追加しました) に変更すると、コンパイルされますfold(authenticated)(unauthenticated)(request)
。fold(authenticated)(unauthenticated).apply(request)
なぜこうなった?クラスで () と .apply() を呼び出すのは同じはずですよね?
コンパイラは、CanBeAuthenticatedRequest の型ではなく、戻り値の型 (Int または Option[Int]) を PartialFunction に渡すように求めているようです。