Scala - 从泛型类型获取类对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8208179/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Scala - obtaining a class object from a generic type
提问by dhg
Is it possible to create a Class object purely from a generic parameter? For example:
是否可以仅从泛型参数创建 Class 对象?例如:
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.
我怀疑这种失败是由于,正如 API 指出的那样,m.erasure的结果类型和T.
EDIT: I'm not really interested in what the type Tis, I just need an object of type Class[_ <: T]to pass to a method in the hadoop framework.
编辑:我对类型不是很感兴趣T,我只需要一个类型的对象Class[_ <: T]来传递给 hadoop 框架中的方法。
Any pointers?
任何指针?
采纳答案by Tom Crockett
You can cast the result of m.erasureto a Class[T]:
您可以将结果转换m.erasure为 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:
但请注意,如果我使用实例化类型构造函数,例如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 Classobject for all the possible instantiations of a given type constructor.
由于擦除,Class给定类型构造函数的所有可能实例化只有一个对象。
Edit
编辑
I'm not sure why Manifest[T].erasurereturns Class[_]instead of Class[T], but if I had to speculate, I would say it's to discourage you from using the methods on Classwhich allow you to compare two classes for equality or a subtype relationship, since those methods will give you wrong answers when the Classis parameterized with an instantiated generic type.
我不确定为什么Manifest[T].erasure返回Class[_]而不是Class[T],但如果我不得不推测,我会说这是为了阻止您使用Class允许您比较两个类的相等性或子类型关系的方法,因为这些方法会给你错误当Class用实例化的泛型类型参数化时回答。
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 Manifests instead and compare them, since they have more information*:
这些结果可能会让您感到惊讶和/或导致您的程序出现错误。不要以这种方式比较类,您通常应该只传递Manifests 并比较它们,因为它们有更多信息*:
scala> manifest[List[String]] == manifest[List[Int]]
res27: Boolean = false
scala> manifest[List[String]] >:> manifest[List[Int]]
res28: Boolean = false
As I understand it, Manifests are meant to supersede Classes 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 erasureis just a sort of "acknowledgement of liability" that you're using an inferior product at your own risk :)
据我了解,对于大多数用例,Manifests 旨在取代Classes ……但是当然,如果您使用的框架需要 a Class,则没有太多选择。我认为强制转换结果erasure只是一种“承认责任”,您使用劣质产品的风险由您自己承担:)
* Note that, as the documentation for Manifestsays, 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."
* 请注意,正如Manifest的文档所说,这些清单比较运算符“应仅被视为近似值,因为类型一致性的许多方面尚未在清单中充分表示。”
回答by Ali Salehi
def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
回答by missingfaktor
.erasuregives you the type to which your type erases to. If you want a full type information, you should return the Manifestinstead.
.erasure给你你的类型擦除的类型。如果你想要一个完整的类型信息,你应该返回Manifest代替。
scala> class MyClass[A] {
| def stuff(implicit m: Manifest[A]): Class[_] = m.erasure
| }
defined class MyClass
scala> new MyClass[Int].stuff
res551: java.lang.Class[_] = int
scala> new MyClass[List[Int]].stuff
res552: java.lang.Class[_] = class scala.collection.immutable.List
scala> class MyClass[A] {
| def stuff(implicit m: Manifest[A]): Manifest[A] = m
| }
defined class MyClass
scala> new MyClass[Int].stuff
res553: Manifest[Int] = Int
scala> new MyClass[List[Int]].stuff
res554: Manifest[List[Int]] = scala.collection.immutable.List[Int]

