【问题标题】:Problems with manifests/typetags when updating to Scala 2.10更新到 Scala 2.10 时的清单/类型标签问题
【发布时间】:2013-07-27 14:26:03
【问题描述】:


我正坐在一个大约 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?即:如果我只使用清单进行类型检查(第 3 条)和​​名称提取(第 2 条):我能否将每个清单/ClassManifest 重命名为 ClassTag?

【问题讨论】:

    标签: scala manifest scala-2.10


    【解决方案1】:
    1. 是的,大多数情况下,TypeTag <-> ManifestClassTag <-> ClassManifest 是等价的。除了以前由 Manifest 处理的某些事情没有直接等效项,因为这些操作被移到了反射 API 的更深处,例如 Manifest 对象上的工厂方法。

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

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

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

      请参阅反射指南中关于 Common Operations on Types 的部分,以及 SO 问题 What is a TypeTag and how do I use it

    4. 我认为没有直接的方法可以从 TypeTag 转到 ClassTag。这样想:

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

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

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

        编辑:我刚刚找到this SO question,所以是的,可以从TypeTag 中获得ClassTag。很遗憾,反射库中没有任何辅助方法。

        编辑 2:根据要求,这里是如何从 TypeTag 转换为 ClassTag

        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
        }
        

    【讨论】:

    • 我遇到了另一个问题:如何重写i.erasure,其中 i 是一个隐式 Manifest[T]
    • 你应该用隐含的ClassTag[T] 替换隐​​含的Manifest[T] 并调用i.runtimeClass
    • 谢谢,除了一件事,一切都已解决:在一种方法中,我有一个TypeTag T,但我需要manifest[T].erasure 的吊坠。通常我会使用classTag[T].runtimeClass,但这次我不会将TypeTag重命名为ClassTag(因为该方法是一个apply函数,很多方法都调用这个apply函数)
    • @user2625693 您可以从TypeTag 获得ClassTag,请参阅我的编辑。
    • @gourlaysama,如果你使用runtimeMirror(getClass.getClassLoader),你很容易出现类加载错误,因为T(它是由用户指定的,毕竟)可以被任何类加载器加载,不仅使用classTag2 方法加载类的那个。你最好改用typeTag[T].mirror
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    相关资源
    最近更新 更多