我在scala generics中迷失了。
我需要一个方法storeUnit
接受Unit
的子类的实例(eq Visit
)并返回StoredUnit
的子类的实例(eq StoredVisit
)但我收到编译错误。
trait StatsUnit { val ip: String }
case class Visit(ip: String) extends StatsUnit
case class Click(ip: String) extends StatsUnit
trait StoredStatsUnit extends StatsUnit { val id: String }
case class StoredVisit(id: String, ip: String) extends StoredStatsUnit
case class StoredClick(id: String, ip: String) extends StoredStatsUnit
def storeUnit[A <: StatsUnit, B <: StoredStatsUnit](statsUnit: A): B = {
statsUnit match {
case x: Visit => StoredVisit("myid", x.ip)
case x: Click => StoredClick("myid", x.ip)
}
}
/tmp/1.scala:11: error: type mismatch;
found : this.StoredVisit
required: B
case x: Visit => StoredVisit("myid", x.ip)
^
/tmp/1.scala:12: error: type mismatch;
found : this.StoredClick
required: B
case x: Click => StoredClick("myid", x.ip)
答案 0 :(得分:3)
首先发表评论:
Unit
! Unit
在Scala中具有特定含义 - 它等同于Java的void
- 并且该定义只会导致麻烦!但是,这里的问题是您指定您的方法将返回B
的实例,然后您尝试返回StoredVisit
类型的内容。在此示例中,您根本不需要B
,因此以下内容可以正常工作:
def storeUnit[A <: StatsUnit](unit: A): StoredStatsUnit = {
StoredVisit("myid", unit.ip)
}
答案 1 :(得分:3)
scala> def storeUnit[A <: StatsUnit, B <: StoredStatsUnit](unit: A): B = {
| StoredVisit("myid", unit.ip).asInstanceOf[B]
| }
storeUnit: [A <: StatsUnit, B <: StoredStatsUnit](unit: A)B
现在让我们创建另一个StoredStatsUnit
的子类:
case class UnStoredVisit(id: String, ip: String, n: Int) extends StoredStatsUnit
现在让我们说明编译器抱怨该方法定义的原因:
scala> val visit: UnStoredVisit = storeUnit(Visit("1.2.3.4"))
java.lang.ClassCastException: StoredVisit cannot be cast to UnStoredVisit
换句话说,你不返回一个参数化的B,它是StoredStatsUnit
的任意子类。您正在返回StoredVisit
,这是它的一个特定子类。
答案 2 :(得分:1)
B
是StoredUnit
的子类型,StoredVisit
是[{1}}的子类型,但没有StoredUnit
与{{1}兼容的有效推断}}