Scala - 从泛型类型获取类对象

发布于 2024-12-17 05:08:10 字数 565 浏览 0 评论 0原文

是否可以纯粹从泛型参数创建一个 Class 对象?例如:

class myclass[T] { 
  def something(): Class[_ <: T] = 
    classOf[T] //this doesn't work
}

由于类型将在运行时被删除,因此这似乎是清单的工作,但我还没有找到演示这种特殊用法的示例。我尝试了以下方法,但它也不起作用:

class myclass[T] { 
  def something()(implicit m: Manifest[T]): Class[_ <: T] = 
    m.erasure //this doesn't work
}

我怀疑此失败是由于,正如 API 指出的那样,m.erasure 结果的类型与T

编辑:我对 T 类型并不是很感兴趣,我只需要一个 Class[_ <: T] 类型的对象来传递给中的方法hadoop 框架。

有什么指点吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半城柳色半声笛 2024-12-24 05:08:10
def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass
林空鹿饮溪 2024-12-24 05:08:10

您可以将 m.erasure 的结果转换为 Class[T]

class myclass[T] { 
    def something()(implicit m: Manifest[T]): Class[T] = 
        m.erasure.asInstanceOf[Class[T]]
}

这对于基本(非泛型)类型效果很好:

scala> new myclass[String]().something()
res5: Class[String] = class java.lang.String

但请注意,如果我使用实例化类型构造函数,例如 TList[String]

scala> new myclass[List[String]]().something()
res6: Class[List[String]] = class scala.collection.immutable.List

由于擦除,对于给定的所有可能实例化,只有一个 Class 对象类型构造函数。

编辑

我不确定为什么 Manifest[T].erasure 返回 Class[_] 而不是 Class[T],但如果我有推测,我想说这是为了阻止您使用 Class 上的方法,这些方法允许您比较两个类的相等性或子类型关系,因为当 使用实例化的泛型类型进行参数化。

例如,

scala> classOf[List[String]] == classOf[List[Int]]
res25: Boolean = true

scala> classOf[List[String]].isAssignableFrom(classOf[List[Int]])
res26: Boolean = true

这些结果可能会让您感到惊讶和/或导致您的程序出现错误。您通常应该传递 Manifest 并比较它们,而不是以这种方式比较类,因为它们有更多信息*:

scala> manifest[List[String]] == manifest[List[Int]]
res27: Boolean = false

scala> manifest[List[String]] >:> manifest[List[Int]]
res28: Boolean = false

据我了解,Manifest 的意思是在大多数用例中取代 Class...但是,当然,如果您使用的框架需要 Class,则没有太多选择。我认为强行强制删除擦除的结果只是一种“责任确认”,您使用的是劣质产品,风险由您自己承担:)

*请注意,作为< a href="http://www.scala-lang.org/api/current/scala/reflect/Manifest.html" rel="nofollow noreferrer">Manifest 文档 说,这些清单比较运算符“应该被考虑只是近似值,因为类型一致性的许多方面尚未在清单中充分体现。”

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 Manifests 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, 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 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."

墨落成白 2024-12-24 05:08:10

.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]

.erasure gives you the type to which your type erases to. If you want a full type information, you should return the Manifest instead.

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]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文