更新到Scala 2.10时清单/类型标记出现问题

fun*_*nyF 4 scala manifest scala-2.10


我坐在一个大约10000 LoC的项目前.我必须将此项目从Scala 2.9更新到2.10.这样做得很好,但由于清单,我收到了许多弃用警告.

在使用stackoverflow和许多其他站点的搜索功能之后,我没有那么多问题.我想总结一下; 关键点是:

  1. TypeTags和ClassTag比Manifest和ClassManifest好得多.特别是你可以使用这些作为同义词(TypeTags < - > Manifests和ClassTags < - > ClassManifest)

  2. TypeTag比ClassTag更强大,ClassTag更受限制TypeTags.我的第一个问题:在这个项目中,manifest[T].erasure.getSimpleName经常使用这种方法.现在我不仅可以将其切换为,typeTag[T].runtimeClass.getSimpleName因为代码不会编译,但是classTag[T].runtimeClass.getSimpleName它会编译.这会影响语义吗?(注意:该方法erasure也已弃用;您必须使用该方法runtimeClass)

  3. 第二个问题: Scala 2.9中的清单类型检查是:manifest[T] <:< manifest[A].在Scala 2.10中,我会写这个typeOf[T] <:< typeOf[A].但是<:<被弃用了?!

  4. 我可以将TypeTag转换为ClassTag吗?即:如果我只使用清单进行类型检查(Nr.3)和名称提取(Nr.2):我能将每个Manifest/ClassManifest重命名为ClassTag吗?

gou*_*ama 5

  1. 是的,你大多有等价TypeTag <-> ManifestClassTag <-> ClassManifest.除了有些东西过去由Manifest处理,没有直接的等价物,因为这些操作被深入到反射API中,就像Manifest对象上的工厂方法一样.

  2. ClassTag现在基本上只用于获取运行时(擦除)类的东西.它主要用于创建数组,但您可以毫无问题地将其用于其他目的.所以,是的,classTag[T].runtimeClass是新的manifest[T].erasure,完全等同于它.

  3. 这是变化最大的地方.2.10引入了新的反射API,当你想回答关于类型的特定问题时,你应该使用它(比如" A <:< B吗?").并且类型的反射API的入口点是......它的TypeTag.

    假设类型标签适用于A并且T在范围内,新的manifest[T] <:< manifest[A]确实如此typeOf[T] <:< typeOf[A].<:<此处不推荐使用该方法,请参阅scaladoc.然而有一个被弃用<:<ClassTag因为ClassManifest曾经有一个,而且ClassTag是新的ClassManifest.

    请参阅有关反射指南类型常见操作部分,以及SO问题什么是TypeTag以及如何使用它.

  4. 我不认为有一种直接的方式从a TypeTag到a ClassTag.想一想:

    • 如果你需要子类型或类型相等检查,你不能使用a ClassTag,你需要一个TypeTag;

    • 如果你还需要那个类型的名字,你可以从TypeTag:typeOf[T].typeSymbol.name.decoded.这将为您提供已删除的名称,就像您以前获取的类名(Listfor List[Int]Mapfor Map[String, Int])一样.这与获取实际名称略有不同Class.如果你需要完整的未擦除名称(List[Int]),typeOf[T].normalize.toString就足够了.

    • 如果你也绝对需要一个Class实例,或者你可以传递的真实类名,稍后用反射加载,我想你别无选择,只能要求一个ClassTag...

      编辑:我刚刚发现了这个问题,所以是的,有可能ClassTag从a 获得TypeTag.遗憾的是,反射库中没有任何辅助方法.

      编辑2:根据要求,以下是如何转换TypeTagClassTag:

      import reflect.runtime.universe._
      import reflect.ClassTag
      
      def classTag2[T: TypeTag]: ClassTag[T] = {
        ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
      }
      
      // example:
      
      def doSomething[T : TypeTag] = {
        val c = classTag2[T]
        c.runtimeClass.getName
      }
      
      Run Code Online (Sandbox Code Playgroud)