我有以下代码:
trait Base[A,B] {
def name: String
}
trait BaseCompanion[A,B] {
def classOfBase: Class[_ <: Base[A,B]] // Can I implement something generic here ?
}
case class First(name: String) extends Base[Int,String]
object First extends BaseCompanion[Int,String] {
override def classOfBase: Class[_ <: Base[Int, String]] = classOf[First] // Can this part be generic ?
}
我不希望在每个具有classOfBase
的具体类中覆盖BaseCompanion
方法。这可以通过将BaseCompanion
更改为:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
}
object First extends BaseCompanion[Int,String,First]
但我不是非常喜欢这个解决方案,有没有办法在不更改BaseCompanion
的签名的情况下执行此操作并在其中实现通用内容?
顺便说一句,今天Companion对象的任何案例类&#34;定义&#34; apply(...)
方法。鉴于上面的例子,将有一个类似的方法:
abstract class BaseCompanion[A,B, CLAZZ <: Base[A,B] : ClassTag] {
def classOfBase: Class[CLAZZ] = classTag[CLAZZ].runtimeClass.asInstanceOf[Class[CLAZZ]]
/* No need to implement in the companion of a case class that extends Base */
def apply(name: String): Base[A,B]
}
Companion知道这个apply
方法的返回类型,也许有一种方法可以使用这些信息。
答案 0 :(得分:1)
假设如果您想要的是什么,可以采用以下方法:
case class First(name: String) extends Base[Int, String]
object First extends BaseCompanion[Int, String]
assert(First.baseClass == classOf[First])
现在如果会起作用,会阻止你做以下事情吗?
class Second extends BaseCompanion[Int, String]
val second = new Second
println(second.baseClass)
或
// case class Third not defined
object Third extends BaseCompanion[Int, String]
println(Third.baseClass)
会导致什么结果? Second
和Third
不是具有关联类的伴随对象。 Second
本身就是一个类!
问题是你不能强迫你的BaseCompanion
特征只能被作为伴侣对象的东西继承。因此BaseCompanion
不能使用伴随对象和关联类具有的特殊关系。如果您想获得有关伴随对象的关联类的信息,则必须在随播对象的定义中手动提供BaseCompanion
该信息
Scala编译器不允许您这样做。如果需要,您可以使用反射来解决这个问题,但无论如何,实现这一点的解决方案必须考虑到您有效地创建了不可预测的运行时行为。在我看来,最好只是帮助编译器弄清楚它,并在编译时提供适当的信息。
答案 1 :(得分:1)
是的,可以通过此更改完成:
def classOfBase = this.getClass.getMethods.find(_.getName == "apply").get.
getReturnType.asInstanceOf[Class[_ <: Base[A,B]]]
请注意,这假设只有一个apply
方法。在实践中,您应该检查这个假设。