Scala - 从泛型类型中获取类对象 [英] Scala - obtaining a class object from a generic type
问题描述
是否可以纯粹从泛型参数创建一个Class对象?例如:
class myclass [T] {
def something():Class [_<:T] =
classOf [T] //这不起作用
}
由于这个类型在运行时会被擦除,看起来这是一个清单工作,但我还没找到一个演示这种特殊用法的例子。我尝试了以下,但它也不起作用:
class myclass [T] {
def something( )(implicit m:Manifest [T]):Class [_<:T] =
m.erasure //这不起作用
}
我怀疑这是由于API指出, m.erasure类型之间没有子类型关系的结果和
T
。
编辑:我对什么类型的 T
是,我只需要一个类型为 Class [_<:T]
的对象来传递给一个在hadoop框架中的方法。
任何指针?
您可以将 m.erasure
的结果转换为 Class [T]
:
class myclass [T] {
def something()(implicit m:Manifest [T]):Class [T] =
m .erasure.asInstanceOf [Class [T]]
}
非转基因neric)类型:
scala> new myclass [String]()。something()
res5:Class [String] = class java.lang.String
但是请注意,如果我为 T
List [String] 这样的实例化类型构造函数会发生什么>:
scala> new myclass [List [String]]()。something()
res6:Class [List [String]] = class scala.collection.immutable.List
由于擦除,对于给定类型构造函数的所有可能的实例,只有一个 Class
对象。 / p>
编辑
我不确定为什么 Manifest [T] .erasure
返回 Class [_]
而不是 Class [T]
,但是如果我必须推测,我会说这是为了阻止你使用 Class
上的方法,它们允许你比较两个类是否相等或是一个子类型关系,因为这些方法在 Class
使用实例化的泛型类型进行参数化。
例如,
scala> classOf [List [String]] == classOf [List [Int]]
res25:Boolean = true
scala> classOf [List [String]]。isAssignableFrom(classOf [List [Int]])
res26:Boolean = true
这些结果可能会让您感到惊讶,并且/或者导致程序中出现错误。而不是像这样比较类,你通常应该传递 Manifest
s来比较它们,因为它们有更多的信息*:
scala> manifest [List [String]] == manifest [List [Int]]
res27:Boolean = false
scala> manifest [List [String]]>:>清单[List [Int]]
res28:Boolean = false
据我所知,对于大多数用例, Manifest
s意味着取代 Class
es ......但是当然,如果您正在使用一个需要 Class
的框架,没有多少选择。我假设强制转换擦除结果
的结果只是一种承担责任,即您使用劣质产品时需要您自担风险:
*请注意,正如文件清单中说,这些清单比较操作符应该只被认为是近似值,因为类型一致性的许多方面尚未在清单中充分表示。
Is it possible to create a Class object purely from a generic parameter? For example:
class myclass[T] {
def something(): Class[_ <: T] =
classOf[T] //this doesn't work
}
Since the type will have been erased at runtime, it seems like this a job for manifests, but I haven't found an example that demonstrates this particular usage. I tried the following, but it doesn't work either:
class myclass[T] {
def something()(implicit m: Manifest[T]): Class[_ <: T] =
m.erasure //this doesn't work
}
I suspect this failure is due to, as the API points out, there is no subtype relationship between the type of m.erasure
's result and T
.
EDIT: I'm not really interested in what the type T
is, I just need an object of type Class[_ <: T]
to pass to a method in the hadoop framework.
Any pointers?
You can cast the result of m.erasure
to a Class[T]
:
class myclass[T] {
def something()(implicit m: Manifest[T]): Class[T] =
m.erasure.asInstanceOf[Class[T]]
}
This works fine for basic (non-generic) types:
scala> new myclass[String]().something()
res5: Class[String] = class java.lang.String
But note what happens if I use an instantiated type constructor like List[String]
for T
:
scala> new myclass[List[String]]().something()
res6: Class[List[String]] = class scala.collection.immutable.List
Due to erasure, there is only one Class
object for all the possible instantiations of a given type constructor.
Edit
I'm not sure why Manifest[T].erasure
returns Class[_]
instead of Class[T]
, but if I had to speculate, I would say it's to discourage you from using the methods on Class
which allow you to compare two classes for equality or a subtype relationship, since those methods will give you wrong answers when the Class
is parameterized with an instantiated generic type.
For example,
scala> classOf[List[String]] == classOf[List[Int]]
res25: Boolean = true
scala> classOf[List[String]].isAssignableFrom(classOf[List[Int]])
res26: Boolean = true
These results might surprise you and/or lead to a bug in your program. Instead of comparing classes this way, you should normally just pass around Manifest
s instead and compare them, since they have more information*:
scala> manifest[List[String]] == manifest[List[Int]]
res27: Boolean = false
scala> manifest[List[String]] >:> manifest[List[Int]]
res28: Boolean = false
As I understand it, Manifest
s are meant to supersede Class
es for most use cases... but of course, if you're using a framework that requires a Class
, there's not much choice. I would suppose that the imposition of casting the result of erasure
is just a sort of "acknowledgement of liability" that you're using an inferior product at your own risk :)
* Note that, as the documentation for Manifest says, these manifest comparison operators "should be considered approximations only, as there are numerous aspects of type conformance which are not yet adequately represented in manifests."
这篇关于Scala - 从泛型类型中获取类对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!