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

アレッ*_*ックス 9 scala type-erasure type-parameter type-members

这很好用

class MyClass[T<: Actor: ClassTag] extends Actor {
  //....
}
Run Code Online (Sandbox Code Playgroud)

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

class MyClass extends Actor {
  type T<: Actor
  //...
}
Run Code Online (Sandbox Code Playgroud)

即使执行以下操作:

class MyClass extends Actor {
  type T<: Actor: ClassTag //this doesn't even compile
  //...
}
Run Code Online (Sandbox Code Playgroud)

我如何使用摘要type并摆脱错误?

0__*_*0__ 8

class M[A <: B: C]
Run Code Online (Sandbox Code Playgroud)

是的缩写

class M[A <: B](implicit c: C[A])
Run Code Online (Sandbox Code Playgroud)

因此,如果您转移A到抽象类型成员,则必须编写类似的内容

abstract class M {
  type A <: B
  implicit protected def c: C[A]
}
Run Code Online (Sandbox Code Playgroud)

并要求任何人实施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
   }
 }
Run Code Online (Sandbox Code Playgroud)

如果你删除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)
Run Code Online (Sandbox Code Playgroud)

此处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]
}
Run Code Online (Sandbox Code Playgroud)

如果您的子类再次通用的,则需要传递提供类标记的责任:

class GenericClass[A1](implicit val tag: reflect.ClassTag[A1]) {
  type A = A1
}
Run Code Online (Sandbox Code Playgroud)