【问题标题】:In Scala, How to reference the ClassTag of implemented abstract type in all subclasses?在Scala中,如何在所有子类中引用实现的抽象类型的ClassTag?
【发布时间】:2016-09-16 01:13:46
【问题描述】:

如果我有 1 个特征和 2 个对象:

trait MyClass {
  type T <: MyClass

  def foo(): ClassTag[T] = {...}
}

object ChildClass1 extends MyClass {
   type T = String
}

object ChildClass2 extends MyClass {
   type T = Option[String]
}

是否可以在 MyClass 中实现 foo(),使得 ChildClass1.foo() 产生 ClassTag[String],而 ChildClass2.foo() 产生 ClassTag[Option]。

如果没有,最简单的绕过方法是什么?需要注意的是,T的实现可能是内部类/对象,所以hacking反射可能会有一些副作用。

【问题讨论】:

  • 为什么首先需要反思?在 Scala 中,通常有一种解决方法。
  • 是的,虽然重复编译器应该知道的内容更冗长且不必要

标签: scala type-erasure abstract-type


【解决方案1】:

好的,我可能不完全理解您的目标,但据我所知,您正在尝试创建具有上限类型的特征,并且您还希望能够在运行时获取该类型,对吗?

假设你有一个Foo trait:

class MyClass // not important

trait Foo[T <: MyClass] {
  def foo: ClassTag[T]
}

如果你想要一个对象实现,解决方案很简单,因为你在编译时就知道类型:

class MyClassSubclass extends MyClass // also not important

object FooObject extends Foo[MyClassSubclass] {
  def foo: ClassTag[MyClassSubclass] = ClassTag(classOf[MyClassSubclass])
}

但是如果你想要一个类,那么你可以用implicitly + 上下文绑定组合以一种非常易读的方式解决问题:

class FooImpl[T <: MyClass : ClassTag] extends Foo[T] {
  def foo: ClassTag[T] = implicitly[ClassTag[T]]
}

【讨论】:

  • 这看起来不错,但在我的实现中 def foo: ClassTag 可以省略。简单总是可取的
【解决方案2】:

我想提出一个肮脏和受损的答案,如果您有更好的想法,请告诉我:

  lazy val mf: ClassTag[T] = {

    val clazz = this.getClass
    val name = clazz.getName
    val modifiedName = name + "T"
    val reprClazz = Utils.classForName(modifiedName)

    Manifest.classType(reprClazz)
  }

仅当子类是单例对象时才有效。

【讨论】:

    猜你喜欢
    • 2015-06-04
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    相关资源
    最近更新 更多