简体   繁体   English

从类实例导入通用隐式

[英]Importing generic implicits from class instances

I'm trying to make a generic implicit provider which can create an implicit value for a given type, something in the lines of: 我正在尝试创建一个通用的隐式提供程序,该提供程序可以为给定类型创建隐式值,如下所示:

trait Evidence[T]

class ImplicitProvider[T] {
  class Implementation extends Evidence[T]
  implicit val evidence: Evidence[T] = new Implementation
}

To use this implicit, I create a val provider = new ImplicitProvider[T] instance where necessary and import from it import provider._ . 要使用此隐式,我在必要时创建一个val provider = new ImplicitProvider[T]实例,并从中import provider._ This works fine as long as there is just one instance. 只要只有一个实例,此方法就可以正常工作。 However sometimes implicits for several types are needed in one place 但是有时在一个地方需要几种类型的隐式

case class A()
case class B()

class Test extends App {
  val aProvider = new ImplicitProvider[A]
  val bProvider = new ImplicitProvider[B]

  import aProvider._
  import bProvider._

  val a = implicitly[Evidence[A]]
  val b = implicitly[Evidence[B]]
}

And this fails to compile with could not find implicit value for parameter and not enough arguments for method implicitly errors. 而且无法编译, could not find implicit value for parameternot enough arguments for method implicitly错误not enough arguments for method implicitly

If I use implicit vals from providers directly, everything starts to work again. 如果我直接使用提供程序的隐式val,那么一切都会再次开始工作。

implicit val aEvidence = aProvider.evidence
implicit val bEvidence = bProvider.evidence

However I'm trying to avoid importing individual values, as there are actually several implicits inside each provider and the goal is to abstract them if possible. 但是,我试图避免导入单个值,因为每个提供程序中实际上都有多个隐式对象,目标是在可能的情况下抽象它们。

Can this be achieved somehow or do I want too much from the compiler? 可以通过某种方式实现,还是我希望编译器提供太多?

The issue is that when you import from both objects, you're bringing in two entities that have colliding names: evidence in aProvider and evidence in bProvider . 问题是,当你从两个对象导入,你就带来两个实体已经发生碰撞的名字: evidenceaProviderevidencebProvider The compiler cannot disambiguate those, both because of how its implemented, and because it'd be a bad idea for implicits, which can already be arcane, to be able to do things that cannot be done explicitly (disambiguating between clashing names). 编译器不能消除它们的歧义,这不仅是因为其实现方式,而且因为对于隐式对象(可能已经是奥秘的)而言,要能够执行无法显式完成的工作(在冲突的名称之间进行歧义化),这不是一个好主意。

What I don't understand is what the point of ImplicitProvider is. 我不明白的是ImplicitProvider的意义是什么。 You can pull the Implementation class out to the top level and have an object somewhere that holds the implicit val s. 您可以拉动Implementation类向顶层,有一个object的地方,保持implicit val秒。

class Implementation[T] extends Evidence[T]

object Evidence {
  implicit val aEvidence: Evidence[A] = new Implementation[A]
  implicit val bEvidence: Evidence[B] = new Implementation[B]
}

// Usage:
import Evidence._
implicitly[Evidence[A]]
implicitly[Evidence[B]]

Now, there is no name clash. 现在,没有名称冲突。

If you need to have an actual ImplicitProvider , you can instead do this: 如果您需要一个实际的ImplicitProvider ,则可以执行以下操作:

class ImplicitProvider[T] { ... }

object ImplicitProviders {
  implicit val aProvider = new ImplicitProvider[A]
  implicit val bProvider = new ImplicitProvider[B]

  implicit def ImplicitProvider2Evidence[T: ImplicitProvider]: Evidence[T]
    = implicitly[ImplicitProvider[T]].evidence
}

// Usage
import ImplicitProviders._
// ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM