簡體   English   中英

scala:對象的匹配類型參數

[英]scala : Match type argument for an object

如果我有一個類接受一個Type參數,例如Seq[T] ,我有很多這個類的對象。 我想根據類型Argument T拆分它們

例如 :

val x = List(Seq[Int](1,2,3,4,5,6,7,8,9,0),Seq[String]("a","b","c"))
x.foreach { a => 
  a match{ 
    case _ : Seq[String] => print("String") 
    case _ : Seq[Int] => print("Int")  
   }
 }

這段代碼的結果是StringString 它只匹配Seq類而不是Type類型,我該怎么做才能強制它匹配Type?

你看到的是由於Type Erasure( http://docs.oracle.com/javase/tutorial/java/generics/erasure.html )而發生的,一些IDE會警告你這些錯誤。

您可以查看清單,例如查看Scala中的什么是Manifest,何時需要它?

編輯:像Patryk說的那樣,TypeTag取代了Scala 2.10中的Manifest,請參閱Scala:什么是TypeTag以及如何使用它?

TypeTag方法

Java運行時需要泛型類型參數擦除。 Scala編譯器通過將類型信息“注入”到使用TypeTag類型arg聲明的方法來解決TypeTag

def typeAwareMethod[T: TypeTag] (someArg: T) { 
  ... // logic referring to T, the type of varToCheck
}

(或者,可以使用等效的,更長篇的隱式參數 - 未顯示)

當scala編譯具有(1)類型arg [T: TypeTag]和(2)normal arg someArg: T的方法的調用時,它從調用上下文收集someArg類型param元數據,並使用此元數據擴充類型arg T T的值加標簽數據是從調用中推斷出的外部類型:

val slimesters = List[Reptile](new Frog(...), new CreatureFromBlackLagoon(...))
typeAwareMethod(slimesters)

邏輯參考T(在上面的方法中) - 運行時反射

import scala.reflection.runtime.universe._ :類型為scala.relection.api.JavaUniverse的Universe對象的scala.relection.api.JavaUniverse 注意:受進化API變化的影響

  1. 直接TypeTag比較:標簽信息可以通過方法typeTag[T] ,然后直接測試/模式匹配與其他類型標簽的(精確)相等:

     val tag: TypeTag[T] = typeTag[T] if (typeTag[T] == typeTag[List[Reptile]]) ... typeTag[T] match { case typeTag[List[Reptile]] => ... } 

    限制:不能識別子類型(上面與List[Frog]不匹配); 沒有可通過TypeTag獲得的其他元數據。

  2. 更智能的類型比較操作:

    通過typeOf[T] (或typeTag[T].tpe )轉換為Type 然后使用Type ops的gammut,包括模式匹配。 注意:在反射類型空間中, =:=表示類型等效(類似於: ), <:<表示類型一致性(類似於<: :)

     val tType: Type = typeOf[T] // or equivalently, typeTag[T].tpe if (typeOf[T] <:< typeOf[List[Reptile]]) ... // matches List[Frog] typeOf[T] match { case t if t <:< typeOf[List[Reptile]] => ... } // Running Example: def testTypeMatch[T: TypeTag](t: T) = if (typeOf[T] <:< typeOf[Seq[Int]]) "yep!!!" test(List[Int](1, 2, 3)) // prints yep!!! 

    方法仍然需要類型參數[T:TypeTag]或者你將得到世界的類型擦除視圖......

  3. 對類型元數據的反思

    我撒謊2;)。 對於您的情況, typeOf[T]實際上返回TypeRefType的子Type ),因為您實例化了在其他地方聲明的類型。 要獲取完整元數據,您需要將Type轉換為TypeRef

     typeTag[T].tpe match { case t: TypeRef => ... // call t.args to access typeArgs (as List[Type]) case _ => throw IllegalArgumentException("Not a TypeRef") } 
    • 而不是t: TypeRef ,可以通過模式匹配提取零件:

        case TypeRef(prefixType, typeSymbol, typeArgsListOfType) => 
    • Type有方法:

       def typeSymbol: Symbol 
    • 符號有方法:

       def fullName: String def name: Name 
    • 名稱有方法:

       def decoded: String // the scala name def encoded: String // the java name 

解決您的情況

解決方案基於(3):

import scala.reflect.runtime.universe._

def typeArgsOf[T: TypeTag](a: T): List[Type] = typeOf[T] match {
  case TypeRef(_, _, args) => args
  case _ => Nil
}

val a = Seq[Int](1,2,3,4,5,6,7,8,9,0)
val b = Seq[String]("a","b","c")
// mkString & pring for debugging - parsing logic should use args, not strings!
print("[" + (typeArgsOf(a) mkString ",") + "]")
print("[" + (typeArgsOf(b) mkString ",") + "]")

旁白:此測試用例存在問題:

val x = List(Seq[Int](1,2,3,4,5,6,7,8,9,0),Seq[String]("a","b","c"))

x的類型是List [Seq [Any]]。 Any是String和Int的最低共同祖先。 在這種情況下,沒有什么可以反省的,因為所有類型都來自Any,並且沒有其他類型信息可用。 為了獲得更強的輸入,可以通過單獨的變量或元組/對來分離兩個Seq,但是一旦分開,兩者之間就沒有更高階的公共映射/折疊。 “真實世界”案件不應該有這個問題。

我認為這是同樣明智的def ,每個序列類型多個原型一個邏輯,不是去到這些類型擦除的解決方法。 2.10編譯器沒有警告類型擦除,並且在運行時它似乎在我的情況下運行良好。

據推測,這可以避免問題,產生更易理解的代碼。

暫無
暫無

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

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