简体   繁体   中英

How to determine subtype of a type parameter in Scala?

class S
class A extends S
class B extends S

class ClassWithTypeParameter[+T]

val a: ClassWithTypeParameter[S] = new ClassWithTypeParameter[A]

How can one determine the type of the subclass used for the type parameter of value a ?

You cannot because of type erasure . However, I would argue that your attempt to do this is formed from a mis-understanding.

  • The point of a type system is so that the compiler can reason more powerfully about the correctness of your program.
  • In a static type system, each reference has a type which cannot be changed

In your program, there is one reference, a and the type of this reference is ClassWithTypeParameter[S] . That. Is. All. The compiler can know what can be done with this reference. The types are there purely for the compiler. The fact that, at runtime , a was assigned to a value which was a ClassWithTypeParameter[A] is irrelevant.


One possible way of doing this to some approximation (limited by erasure) is to use manifests (called something else in 2.10):

class ClassWithTypeParameter[+T: Manifest] { def erasure = manifest[T].erasure }

Then you can call erasure which will get you a java.lang.Class back. As I said, this is limited. A class is not the same thing as a type and there is no way to distinguish, for example, ClassWithTypeParameter[List[Int]] from ClassWithTypeParameter[List[Double]]

The following is a bad idea (like most uses of reflection) but it works:

class ClassWithTypeParameter[+T: Manifest] {
  def paramIs[V: Manifest] = manifest[T] == manifest[V]
}

Which gives us:

scala> val a: ClassWithTypeParameter[S] = new ClassWithTypeParameter[A]
a: ClassWithTypeParameter[S] = ClassWithTypeParameter@6493c09c

scala> a.paramIs[A]
res0: Boolean = true

scala> a.paramIs[S]
res1: Boolean = false

scala> a.paramIs[B]
res2: Boolean = false

And:

scala> val i = new ClassWithTypeParameter[List[Int]]
i: ClassWithTypeParameter[List[Int]] = ClassWithTypeParameter@260702ee

scala> i.paramIs[List[Int]]
res3: Boolean = true

scala> i.paramIs[List[Double]]
res4: Boolean = false

You could write similar paramSubtypeOf and paramSupertypeOf methods using Manifest 's <:< and >:> .

In Scala 2.10 (Milestone 4 or later) there's a much more flexible way to get the type:

class ClassWithTypeParameter[+T: TypeTag] {
  def paramType = reflect.runtime.universe.typeTag[T].tpe
}

Now you could write things like a.paramType.parents to get the immediate supertypes, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM