繁体   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