【问题标题】:Type class and implicits with singleton type/case object类型类和隐含单例类型/案例对象
【发布时间】:2018-09-27 22:59:52
【问题描述】:

我正在尝试实现一个使用案例对象而不是类的类型类。它有点工作。 但是,当我将 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))
  }
}

【问题讨论】:

  • 如果您花点时间格式化您的代码,您可能会得到更好的答案

标签: scala implicit


【解决方案1】:

这是因为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 都将成为该隐式的候选者,因此它将再次失败。

你需要做的是在你的测试方法中使用一个上下文绑定,而不是一个上限,如下:

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

这意味着 test 接收到一个 T 类型,它是 Builder 类型类的成员,Type1 和 Type2 都是 Builder 类型类的成员,因为里面有一个 Builder[Type1.type] 和一个 Builder[Type2.type]隐式作用域。

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

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


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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • Builder.build 有一个隐式参数。通过使用: Builder 注释类型参数,您是在告诉编译器在范围内查找隐式Builder[T],它可供Builder.build 获取。这是正确的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多