簡體   English   中英

Scala - 從泛型類型中獲取類對象

[英]Scala - obtaining a class object from a generic type

是否可以純粹從泛型參數創建一個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框架中的方法。

有什么指針嗎?

def myClassOf[T:ClassTag] = implicitly[ClassTag[T]].runtimeClass

您可以將m.erasure的結果m.erasureClass[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

但是請注意如果我使用像List[String]這樣的實例化類型構造函數來實現T

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

由於擦除,給定類型構造函數的所有可能實例化只有一個Class對象。

編輯

我不確定為什么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來比較它們,因為它們有更多的信息*:

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

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

據我所知, Manifest s意味着在大多數用例中取代Class es ......當然,如果你使用的是一個需要Class的框架,那就沒有多少選擇了。 我認為強制erasure結果只是一種“承擔責任”,你使用的是劣質產品,風險自負:)

*請注意,正如Manifest文檔所述 ,這些明顯的比較運算符“應僅被視為近似值,因為類型一致性的許多方面尚未在清單中充分表示。”

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM