下面的代码示例显示了我问题的核心:
// This is the base trait that the classes are extending
trait Operation[T] {
def operate(x: T): T
}
// Here are 2 case classes that exist for the sole purpose of being
// the generic type for the classes I'm making
case class CaseClass1(field1_1: String, field1_2: String, field1_3: String)
case class CaseClass2(field2_1: String, field2_2: String, field2_3: String)
// These are the 2 classes that extend my basic trait, implementing the operate
// method with some kind of logic
class FillField1 extends Operation[CaseClass1] {
def operate(input: CaseClass1): CaseClass1 = input.copy(field1_3 = "haha")
}
class FillField2 extends Operation[CaseClass2] {
def operate(input: CaseClass2): CaseClass2 = input.copy(field2_2 = "hoho")
}
import scala.reflect.runtime.universe._
// This is a function that prints out the typetag information currently available
def someFunc[T: TypeTag](x: Operation[T]): Unit = {
println(s"TypeTag is: ${typeOf[T]}")
}
// Here I'm creating a sequence of Operations, but they can have any generic
// type parameter
val someSeq: Seq[Operation[_]] = Seq(new FillField1, new FillField2)
someSeq.map(someFunc(_))
/*
Output:
TypeTag is: _$1
TypeTag is: _$1
* /
someFunc(new FillField1)
/*
Output:
TypeTag is: CaseClass1
* /
如您所见,当我调用someFunc(new fillField1)
时,我可以在运行时正确地找到我的类型标签。但是当我使用someSeq
时,它是一个可以包含多种类型的类的序列,我无法在运行时获得所需的类型标签。这是因为您在运行时丢失了该信息吗?
如何在运行时获得正确的类型标签?那么,当我使用Seq[Operation[_]]
时,如何才能获得TypeTag is: CustomClass1
和TypeTag is: CustomClass2
作为输出呢?
我正在处理一个ApacheSpark项目,其中我们有一个类似的结构,当我使用该序列时,我收到一个问题,即TypeTag指向一个未知的类_$10
(或编译器为我的类型标签命名的任何名称),而不是实际的TypeTag,它应该是CustomClass1
或CustomClass2
……
1条答案
按热度按时间h43kikqp1#
TypeTag
主要做的不是运行时反射,而是将一些信息(一种类型)从编译时持久化到运行时。Seq
是同构集合(即其所有元素都具有相同的类型)。在Seq(new FillField1, new FillField2)
中,两个元素的类型都是Operation[_]
。因此,当应用someFunc
时,T
被推断为_
,也就是_$1
(即存在类型Operation[_]
的未知参数)。因此,一种选择是使用异类集合(
HList
)。然后元素可以有不同的类型,这些类型可以从编译时捕获到运行时,这些类型可以在运行时处理另一种选择是使用运行时反射(即
TypeTag
不能做的事情)另一种实现是
另一个选项是磁铁图案(12345 6 7)
或者,您可以将
someFunc
移动到Operation
内部,将TypeTag
从方法移动到类,并使Operation
成为抽象类