没有ClassTag可用于MyClass.this.T的抽象类型

时间:2013-12-14 06:43:34

标签: scala type-erasure type-parameter type-members

这很好用

class MyClass[T<: Actor: ClassTag] extends Actor {
  //....
}

但这不是由于错误No ClassTag available for MyClass.this.T

造成的
class MyClass extends Actor {
  type T<: Actor
  //...
}

即使执行以下操作:

class MyClass extends Actor {
  type T<: Actor: ClassTag //this doesn't even compile
  //...
}

如何使用抽象type并摆脱错误?

1 个答案:

答案 0 :(得分:8)

class M[A <: B: C]

的缩写
class M[A <: B](implicit c: C[A])

因此,如果将A移动到抽象类型成员,则必须编写类似

的内容
abstract class M {
  type A <: B
  implicit protected def c: C[A]
}

并要求任何实施M的人提供此类 c。如果您希望M非抽象,则必须要求类型为C[A]的构造函数值参数,这反过来意味着类型A必须是构造函数类型参数...


修改以回答评论:符号A : C 已定义扩展为C[A]类型的隐式值参数。 C称为上下文绑定,可以理解为类型C[_]要求类型类A。如果您实施 M,则无需重复implicit修饰符。为什么会这样?让我举个例子,使用一个众所周知的类型类Ordering

 abstract class Foo {
   type A
   implicit protected def ord: Ordering[A]

   protected def seq: Seq[A]

   def range: (A, A) = {
     val xs = seq
     xs.min -> xs.max
   }
 }

如果您删除了implicit,则必须将呼叫更改为xs.minxs.max,这需要隐式Ordering

object Bar extends Foo {
  type A = Int
  val seq = List(8, 34, 5, 21, 3, 13)
  val ord = Ordering.Int  // don't need to repeat `implicit`
}

Bar.range // (3, 34)

此处,Bar显示了如何提供隐式值参数。这对于ClassTag来说是相同的:

trait MyClass {
  type A
  implicit def tag: reflect.ClassTag[A]
}

object StringClass extends MyClass {
  type A = String
  // type String is statically known, thus compiler gives us this:
  val tag = reflect.classTag[String]
}

如果您的子课程通用,则需要传递提供课程标签的责任:

class GenericClass[A1](implicit val tag: reflect.ClassTag[A1]) {
  type A = A1
}