如何将 Scala 泛型类型与特征匹配

How to match scala generic type with trait

这是通过传入DatabaseType 的原始方法。

trait DatabaseComponent

class Database {
  this: DatabaseComponent =>

}

object Database {
  def apply(dbType : DatabaseType): Unit ={
    val database = dbType match {
      case DatabaseType.H2 => new Database with H2Component {}
      case DatabaseType.MySQL => new Database with MySQLComponent {}
      case DatabaseType.PostgresSQL => new Database with PostgresSQLComponent {}
    }
  }
}

但是,我想传入泛型类型并使用 typeOf(T),就像在 C#

中一样
private void Apply<T>(){
   switch(typeOf(T)){
     Something
   }
}

我正在看这个postHow to match scala generic type?

但我仍然不确定这是在做什么。

1) 这个 val string = implicitly[ClassTag[String]]

隐含的是什么

2) 为什么 T 必须是 ClassTag 的子类 implicitly[ClassTag[T]] match {

3) 我应该在这里使用 ClassTag 还是 TypeTag?

1 和 2 有点相同的答案,您可能想阅读有关类型 classes 的内容。这里的类型 class 是 ClassTag[T]。本质上,类型 class 是一个接口,可以通过称为类型 class 的实例的实现 "attached" 到任何类型。在 Scala 中,类型 classes 的实例在隐式范围内查找,因此虽然您可以为一个类型实现多个不同的实例,但可能永远不会有一个以上的实现(或者它是模棱两可的)。如果你写类似

def method[T : TypeClass](p1, p2, ...) 

调用方法时,您强制在作用域中为类型 T 拥有一个 TypeClass 实例。请注意,这相当于

def method[T](p1, p2, ...)(implicit val ev: TypeClass[T]) ...

所以你实际上有一个隐藏的参数,你可以显式地给出它(!)

implicitly[X] 实际上是一种获取当前范围内类型 X 的任何隐式值的方法。你其实可以自己实现:

def yourImplicitly[T](implicit val ev: T) : T = ev

类型 classes 有大量应用程序,因为这是一种富有成效的抽象。您可能想阅读有关 "extension problem" 的内容,因为 type-classes 是 FP 语言扩展问题的解决方案。

实际上,您可以使 DatabaseComponent 本身成为一种类型 class。

  1. 我不太确定这里的答案,您可能需要查看http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html。如果我正确理解你的问题,那么 class 标签可能就足够了(并且更容易使用)。

部分补充@uberwach的回答

与 C# 不同,JVM 具有类型擦除功能,可以在运行时擦除所有类型日期。所以 typeOf 在 Scala 中是不可能的。您不能在运行时创建类型 T 的新实例。

Type erasure: Java vs C#