类型类和具有单例类型/案例对象的隐式

时间:2018-09-26 21:10:39

标签: scala implicit

我正在尝试实现与案例对象而非类一起使用的类型类。这样的作品。 但是,当我将case对象本身传递给该函数时,它将起作用,但是,当我尝试将具有基本特征类型的对象传递给该函数时,它将无法编译。

object Test {

  sealed trait MyType
  case object Type1 extends MyType
  case object Type2 extends MyType

  trait Builder[A] {
    def build: String
  }

  object Builder {
    implicit  val type1Builder: Builder[Type1.type] = new Builder[Type1.type] {
      def build: String = s"building1"
    }

    implicit val type2Builder: Builder[Type2.type] = new Builder[Type2.type] {
      def build: String = s"building2"
    }

    def build[A](a: A)(implicit builder: Builder[A]) = builder.build
  }

  import Builder._

  // Compiles
  def test[T <: MyType](t:Type2.type): Unit = {
    println(Builder.build(t))
  }
  // Doesn't compile - 'could not find implicit value for parameter builder ' 
  def test2[T <: MyType](t:MyType): Unit = {
    println(Builder.build(t))
  }
}

2 个答案:

答案 0 :(得分:1)

这对我有用。不知道为什么

 def test2[T <: MyType : Builder ](t2:T): Unit = {

    println(Builder.build(t2))
  }

答案 1 :(得分:1)

这是因为scala中的类型参数默认情况下是不变的,这意味着:

Builder [Type1.type]不是Builder [MyType]的子类型。

在此代码段中,您需要一个Builder [MyType],而type1Builder和type2Builder都不是Builder [MyType]的子类型:

+----+----+----+
|int1|int2|diff|
+----+----+----+
|   1|   1|   0|
|   1|   1|   0|
|   1|   1|   0|
+----+----+----+

您可以使Builder的类型参数为协变量(Builder [+ A]),但是,type1Builder和type2Builder都是该隐式的候选者,因此它将再次失败。

您需要做的是在测试方法中使用上下文绑定,而不是上限类型,如下所示:

def test[T <: MyType](t:MyType): Unit = {
    println(Builder.build(t))
}

这意味着测试接收到一个T类型,它是Builder类型类的成员,Type1和Type2都是Builder类型类的成员,因为在其中有一个Builder [Type1.type]和Builder [Type2.type]隐式范围。

如果您还想限制测试,以便仅使用def test[T : Builder](t: T): Unit = { println(Builder.build(t)) } 的实现来调用它,则可以同时使用上限类型绑定和上下文绑定:

MyType