1

このアイデアを思いついたときに、プロジェクト (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 に渡すように求めているようです。

4

1 に答える 1

3

`fold[T : Helper]' でバインドされたコンテキストを定義しているため、コンパイラは別のパラメータ リストを追加します。言い換えれば、コンテキスト バウンドは、次の構文糖衣にすぎません。

private def fold[T](authenticated: (AuthenticatedRequest[_]) => T)
                   (unauthenticated: (UnauthenticatedRequest[_]) => T)
                   (implicit helper: Helper[T): PartialFunction[CanBeAuthenticatedRequest[_], T] 

だからあなたが電話するとき

fold(authenticated)(unauthenticated)(request)

コンパイラはrequest、明示的に指定された暗黙の Helper[T] であると想定しています。

于 2015-08-31T11:23:34.643 に答える