Scala泛型亚型

时间:2013-02-07 16:03:39

标签: scala generics types

我在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)

3 个答案:

答案 0 :(得分:3)

首先发表评论:

  1. 不要说出你的特质UnitUnit在Scala中具有特定含义 - 它等同于Java的void - 并且该定义只会导致麻烦!
  2. 但是,这里的问题是您指定您的方法将返回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)

BStoredUnit的子类型,StoredVisit是[{1}}的子类型,但没有StoredUnit与{{1}兼容的有效推断}}