派生类作为类构造函数参数

时间:2017-01-24 03:03:44

标签: scala inheritance

[以下编辑]

我有一个类层次结构,现在大致如下:

sealed trait Foo {
  def method: Any
}

case class Bar extends Foo {
  def method: Array[String] = // implementation
}

case class Baz extends Foo {
  def method: Map[String, Array[String]] = // implementation
}

我给抽象方法一个返回类型Any,因为case类的返回类型必然不同,但它们有着相似的目的。出于这个原因,我希望将其保留在特征中以模拟这种常见行为,这是我发现编译它的唯一方法。我意识到这违反了Scala的类型系统的精神,所以我问下面的第一个问题。

然后,另一个类需要一个Foo的子类作为构造函数参数,除了以下内容之外我不知道如何表示这个:

class Qux(foo: Foo) {
  val m = foo.method
  ...
  ...
}

稍后在类Qux中有一些方法期望val m具有与{{BarBaz的特定子类相对应的类型1}},但我收到像

这样的编译错误
Foo

所以我有几个问题:

  • 我对Scala足够熟悉,相信这是表达我特定问题的正确方法,但不熟悉它以了解如何解决它。做我想做的事情的正确方法是什么?
  • 另外,有没有办法告诉班级... type mismatch; [error] found : Any [error] required: Array[String] Qux应该被视为来自mmethod的特定Bar返回的值,而不是Baz的抽象方法?

编辑:采用@marios建议的方法(使用抽象类型成员)似乎是朝着正确方向迈出的一步,但现在会弹出类型不匹配。在课程Foo中,我现在有

Qux

class Qux[X <: Foo](sc: SparkContext, val foo: X) { val m: foo.A = foo.method def process(rows: DataFrame) = foo match { case Bar(sc, _) => BarProcessor(sc, m).doStuff(rows) case Baz(sc, _) => BazProcessor(sc, m.keys).doStuff(rows, m.values) } } 例如,使用BarProcessor实例化Array[String],而BazProcessor需要Baz&#39; s返回的值中的键值对method要做的事情。但是,我现在遇到像

这样的错误
[error] Qux.scala:4: type mismatch;
[error]  found   : Qux.this.foo.A
[error]  required: Array[String]
[error]     case Bar(sc, _) => BarProcessor(sc, m).doStuff(rows)
[error]                                         ^

当我Map m foo Bazvalue keys is not a member of Qux.this.foo.A时,我尝试拨打m时会显示类似的错误(沿着Array[String]行,等等。)。我了解A并非真正 ...shared/service/cert.service - ...shared/Service/cert.service类型。但有没有办法告诉Scala&#34;翻译&#34;这成为理想的类型?

2 个答案:

答案 0 :(得分:4)

您可以在特征中添加类型参数,如下所示:

sealed trait Foo[A] {
  def method: A
}

case class Bar extends Foo[Array[String]] {
  def method: Array[String]
}

case class Baz extends Foo[Map[String, Array[String]]] {
  def method: Map[String, Array[String]]
}

答案 1 :(得分:4)

访问ADT中各个类型的更简单方法是使用抽象类型成员而不是泛型类型参数

sealed trait Foo {
   type A
   def method: A
}

case object Bar extends Foo {
   type A = Array[String]
   def method: A = Array.empty[String]
}

case object Baz extends Foo {
   type A = Map[String, Array[String]]
   def method: A = Map.empty[String, Array[String]]
}

case class Qux[X <: Foo](foo: X) {
  def m: X#A = foo.method

  // You can then pattern match on m
  def f = m match {
    case a: Baz.A => a.size // Use Baz#A if Baz is a class and not an object
    case b: Bar.A => b.size // Use Bar#A if Bar is a class and not an object
  }
}

使用它(查看返回类型)

@ Qux(Baz).m
res6: Map[String, Array[String]] = Map()

@ Qux(Bar).m
res7: Array[String] = Array()