这很好用
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
并摆脱错误?
答案 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.min
和xs.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
}