我试图在我的系统中理解和合并上界类型与重写,但是没有一些丑陋的代码就无法实现它。我有以下两个特点:
trait MyId {
def getType: Int // For simplicity. This is Enum/Object in code.
def id: Any
}
trait MyTrait {
protected def supportedType: Int
def doSomething(id: MyId): Unit = {
if (id.getType == myType)
doSomethingInternal(id)
}
protected def doSomethingInternal(id: _ <: MyId): Unit
}
和我想创建的子类型为:
class X(x: Long) extends MyId {
override def getType: Int = 1
override def id: Long = x
}
class Y(y: String) extends MyId {
override def getType: Int = 2
override def id: String = y
}
class A extends MyTrait {
override protected def supportedType: Int = 1
override protected def doSomethingInternal(id: X): Unit {...}
}
class B extends MyTrait {
override protected def supportedType: Int = 2
override protected def doSomethingInternal(id: Y): Unit {...}
}
然而,这不起作用。我一直在使用的解决方案是使用asInstanceOf[]
:
class A extends MyTrait {
override protected def supportedType: Int = 1
override protected def doSomethingInternal(id: MyId): Unit {
val id2 = id.asInstanceOf[X]
}
}
class B extends MyTrait {
override protected def supportedType: Int = 2
override protected def doSomethingInternal(id: MyId): Unit {
val id2 = id.asInstanceOf[Y]
}
}
有办法摆脱asInstanceOf[]
吗?
编辑
此外,我有以下处理器,需要根据给定的MyId.getType
调用正确的MyTrait
子类:
def process(ids: Seq[MyId], processors: Map[Int, MyTrait]): Unit = {
ids.foreach{ id =>
processors.get(id.getType).doSomething(id)
}
}
编辑2:
为了简单起见,这里的getType
是Int
。在我的代码中,这实际上是一个枚举/对象。- 将
getSomething
重命名为doSomething
以更清晰。
从问题中不清楚是否有getSomething
和getSomethingInternal
之间的间接特定需要,而不是getType
一致性检查,但由于看起来目标只是为了防止用错误的id类型调用getSomething
,在我看来,用预期id的类型参数定义MyTrait会更简单:
trait MyTrait[T] {
def getSomething(id: T): Unit
}
class A extends MyTrait[Long] {
def getSomething(id: Long): Unit = { println(s"long id: $id") }
}
class B extends MyTrait[String] {
def getSomething(id: String): Unit = { println(s"string id: $id") }
}
事情是这样的:
val a = A()
val b = B()
a.getSomething(123)
// prints "long id: 123"
b.getSomething("abc")
// prints "string id: abc"
a.getSomething("bad") // <--- doesn't compile
b.getSomething(123) // <--- doesn't compile
我不完全清楚你到底想做什么,但是,也许,这样的东西会起作用。关键是使用Type
作为类型,而不是试图将其编码为Int
…然后转换为类型。
trait MyId[Type] {
def id: Type
}
trait MyTrait[T] {
def getSomething(id: MyId[T]): Unit =
getSomethingInternal(id.id)
protected def getSomethingInternal(id: T): Unit
}
再一次,这很大程度上是在黑暗中拍摄,因为我不知道为什么你的类型是数字或为什么你的gets
返回单位…
好的,如果你的类型是"枚举",你想把你的MyId
设置为一个密封的trait:
sealed trait MyId[T] {
def id: T
}
case class X(id: Long) extends MyId[Long]
case class Y(id: String) extends MyId[String]
但是现在您想要统一地处理您的id。如果处理器列表是静态的,只需执行match
:
def process(ids: Seq[MyId[_]]) = ids.map {
case x: X => processX(х)
case y: Y => processY(y)
}
如果不是呢?嗯. .在这种情况下,我会从另一个更新开始回答你的问题,解释你为什么需要它,以及你如何生成这个动态列表。