解析一个隐式,然后使用存储在其中的类型来解析第二个隐式

问题描述 投票:0回答:1

我正在尝试解析隐式,然后使用存储在其中的类型来解析第二个隐式。这是代码:

sealed trait ReturnTypeRetriever[T] {
  type ReturnType
}
object ReturnTypeRetrievers {
  implicit val expl = new ReturnTypeRetriever[ExplorationStreamFilter] {
    type ReturnType = SimpleFilter[Context, Context]
  }
}

sealed trait Retriever[T, +R] {
  def get(config: Config): R //SimpleFilter[Context, Context] 
}
object Retrievers {
  // implementation here for T=ExplorationStreamFilter and R=SimpleFilter[Context, Context]
  implicit val expl = new Retriever[ExplorationStreamFilter, SimpleFilter[Context, Context]] {
    override def get(config: Config) = {..}
  }

  // putting it all together
  def getOrEmpty[A](config: Config)(implicit evret: ReturnTypeRetriever[A]) = {
    val ev = implicitly[Retriever[A, evret.ReturnType]]  <-- ERROR 1: cannot find implicit defined above ^
    ev.get(config)
  }
}

这样称呼:

lazy val exploration = getOrEmpty[ExplorationStreamFilter](config) <--- ERROR 2: cannot find implicit here either

编译显示2个错误:

ERROR 1 message: could not find implicit value for parameter e: Retriever[A,evret.ReturnType]
[error]   val ev = implicitly[Retriever[A, evret.ReturnType]]

ERROR 2 message: could not find implicit value for parameter evret: ReturnTypeRetriever[ExplorationStreamFilter]
[error]   lazy val exploration = getOrEmpty[ExplorationStreamFilter](config)

为什么编译器找不到隐式?有什么解决方案?

scala implicit
1个回答
0
投票

这似乎有效。它使用Aux模式和Partially-applyed技巧。

sealed trait ReturnTypeRetriever[T] {
  type ReturnType
}

// It should be named equally to the trait, in order to be a companion.
// That way, implicits will be in scope.
object ReturnTypeRetriever {
  // Aux pattern!
  // Used to transform a type member, into a type parameter, for better inference.
  type Aux[T, R] = ReturnTypeRetriever[T] { type ReturnType = R }

  // Implicits must always have explicit type signatures.
  implicit final val expl: Aux[ExplorationStreamFilter, SimpleFilter[Context, Context]] =
    new ReturnTypeRetriever[ExplorationStreamFilter] {
      override final type ReturnType = SimpleFilter[Context, Context]
    }
}

sealed trait Retriever[T, +R] {
  def get(config: Config): R
}

object Retriever {
  implicit final val expl: Retriever[ExplorationStreamFilter, SimpleFilter[Context, Context]] =
    new Retriever[ExplorationStreamFilter, SimpleFilter[Context, Context]] {
      override final def get(config: Config): SimpleFilter[Context, Context] =
        ???
    }

  // Ideally, you should make this class private[package]
  // Where package is the package in which this is defined.      
  final class GetOrEmptyPartiallyApplied[A](private val dummy: Boolean) extends AnyVal {
    def apply[R](config: Config)
                (implicit rtr: ReturnTypeRetriever.Aux[A, R], retriever: Retriever[A, R]): R =
      retriever.get(config)
  }

  // Partially-applied trick!
  // Used to allow partial application of a type.
  // User only needs to specify A, the compiler will infer R.
  def getOrEmpty[A]: GetOrEmptyPartiallyApplied[A] =
    new GetOrEmptyPartiallyApplied(dummy = true)
}

(我不理解ReturnTypeRetriever特性的目的是什么,但我保留它来保留原始问题)

© www.soinside.com 2019 - 2024. All rights reserved.