scala - 类型类和带有单例类型/案例对象的隐式

标签 scala implicit

我正在尝试实现一个使用案例对象而不是类的类型类。有点管用。 但是,当我将案例对象本身传递给它起作用的函数时,当我尝试传递具有基本特征类型的对象时,它不会编译。

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

最佳答案

那是因为scala中的类型参数默认是Invariant的,这意味着:

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

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

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

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

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

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

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

如果您还想限制测试,以便您只能使用 MyType 的实现来调用它,您可以同时使用上限类型绑定(bind)和上下文绑定(bind):

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


test(Type1) // building1
test(Type2) // building2

关于scala - 类型类和带有单例类型/案例对象的隐式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52526072/

相关文章:

json - 计算带有 Spark 条件的数据帧的行数

scala - 尾递归 - Scala(任何其他语言)

scala - 隐含和召唤有什么区别?

scala - 为什么这个 Scala 方法的显式调用允许它被隐式解析?

scala - (Scala) IntelliJ IDEA 中的隐式参数菜单项。如何使用它 ?到底有什么好处呢?

scala - 不能在 Scala 中使用表达式 "_ =>"

scala - Akka 流卡夫卡: No configuration setting found for key 'kafka-clients'

scala - 如何深入比较scala.js中的两个类似js的对象?

swift - 在 Swift 中,编译器是否允许您隐式访问要打开的值?

scala - 为什么Scala和sbt可以编译这段代码?