4


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

用了stackoverflow等很多网站的搜索功能后,也没有那么多疑问了。我想总结一下;关键点是:

  1. TypeTags 和 ClassTags 比 Manifests 和 ClassManifest 好得多。特别是您可以将它们用作同义词(TypeTags <-> Manifests 和 ClassTags <-> ClassManifest)

  2. TypeTags 比 ClassTags 更强大,ClassTags 分别是更受限制的 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 吗?

4

1 回答 1

5
  1. 是的,你主要有等价的TypeTag <-> ManifestClassTag <-> ClassManifest. 除了过去由 Manifest 处理的某些事情没有直接等效项,因为这些操作被移到了反射 API 的更深处,例如Manifest对象上的工厂方法。

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

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

    假设AT的类型标签在范围内,那么 newmanifest[T] <:< manifest[A]确实是typeOf[T] <:< typeOf[A]. 该方法<:<在这里不被弃用,请参阅 scaladoc。然而,有一个已弃用<:<ClassTag因为ClassManifest曾经有一个,并且ClassTag是新的ClassManifest.

    请参阅反射指南的关于类型的常见操作部分,以及 SO 问题What is a TypeTag and how do I use it

  4. 我认为从 aTypeTag到 a没有直接的方法ClassTag。这样想:

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

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

    • 如果您还绝对需要一个Class实例或一个真实的类名,您可以传递并稍后通过反射加载,我认为您别无选择,只能要求一个ClassTag..

      编辑:我刚刚发现了这个 SO question,所以是的,可以ClassTagTypeTag. 遗憾的是,反射库中的某个地方没有为此提供帮助方法。

      编辑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
      }
      
于 2013-07-27T15:27:26.007 回答