从类实例导入通用含义

时间:2017-08-21 17:19:48

标签: scala generics typeclass implicit

我正在尝试创建一个通用的隐式提供程序,它可以为给定的类型创建一个隐式值,如下所示:

trait Evidence[T]

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

要使用此隐式,我会在必要时创建一个val provider = new ImplicitProvider[T]实例并从中导入import provider._。只要只有一个实例,这样就可以正常工作。但是,有时需要在一个地方隐含几种类型

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]]
}

这无法使用could not find implicit value for parameternot enough arguments for method implicitly错误进行编译。

如果我直接使用提供者的隐式val,那么一切都会重新开始。

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

但是我试图避免导入单个值,因为每个提供程序中实际存在几个含义,并且目标是在可能的情况下抽象它们。

这可以通过某种方式实现,还是我想从编译器那里得到太多?

1 个答案:

答案 0 :(得分:1)

问题是,当您从这两个对象导入时,您将引入两个具有冲突名称的实体:evidence中的aProviderevidence中的bProvider }。编译器无法消除歧义,无论是因为它的实现方式,还是因为它可能已经很神秘,因为它能够执行无法明确完成的事情(消除冲突名称之间的歧义)

我不明白的是ImplicitProvider的重点。您可以将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]]

现在,没有名字冲突。

如果你需要一个实际的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._
// ...