派生类作为类构造函数参数 [英] Derived classes as class constructor parameters
问题描述
我现在有一个类层次结构,大致如下:
I have a class hierarchy that is, right now, roughly as follows:
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
,因为案例类的返回类型必然不同,但是它们具有相似的目的.出于这个原因,我想将其保留在特征中,以对这种常见行为进行建模,这是我发现对其进行编译的唯一方法.我意识到这与Scala的类型系统的精神背道而驰,所以我问以下第一个问题.
I am giving the abstract method a return type of Any
because the return types of the case classes are necessarily different, but they share a similar purpose. For this reason, I'd like to keep it in the trait to model that common behavior, and this is the only way I've found to make it compile. I realize this is against the spirit of Scala's type system, so I ask the first question below.
然后,另一个类期望Foo
的子类作为构造函数参数,除以下内容外,我不知道如何表示这一点:
Then, another class expects a subclass of Foo
as a constructor parameter, and I do not know how to denote this, other than the following:
class Qux(foo: Foo) {
val m = foo.method
...
...
}
稍后在类Qux
中有些方法期望val m
的类型与Foo
的特定子类(Bar
或Baz
)相对应,但是我遇到编译错误像
Later in the class Qux
there are methods that expect the val m
to be of the type corresponding to the particular subclass (Bar
or Baz
) of Foo
, but I am getting compilation errors like
... type mismatch;
[error] found : Any
[error] required: Array[String]
所以我有几个问题:
- 我对Scala足够熟悉,以为这是代表我的特定问题的正确方法,但是对它却不熟悉,却不知道如何解决.做我想做的事情的正确方法是什么?
- 此外,还有一种方法可以告诉类
Qux
应该将m
视为由Bar
或Baz
的特定method
返回的值,而不是作为Foo
的抽象方法返回的值?
- I am familiar enough with Scala to believe that this is the right way to represent my particular problem, but not familiar enough with it to know how to go about it. What is the proper way to do what I'm trying to do?
- Also, is there a way to tell class
Qux
thatm
should be treated as the value returned by the specificmethod
fromBar
orBaz
, and not the abstract method fromFoo
?
采用@marios建议的方法(使用抽象类型成员)似乎是朝正确方向迈出的一步,但是现在出现了类型不匹配的情况.在课程Qux
中,我现在有了
Taking the approach suggested by @marios (using abstract type members) seems to be a step in the right direction, but a type mismatch pops up now. Within the class Qux
, I now have
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)
}
}
例如,用Array[String]
实例化BarProcessor
的地方,BazProcessor
需要Baz
的method
返回的值中的键值对来完成工作.但是,我现在遇到类似
Where BarProcessor
is instantiated with, for instance, an Array[String]
, and BazProcessor
needs the key-value pairs from the value returned by Baz
's method
to do stuff. However, I am now getting errors like
[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] ^
当foo
是Baz
时(沿着value keys is not a member of Qux.this.foo.A
等),当我尝试在m
上调用特定于Map
的方法时,出现类似的错误.我知道m
并不是真的是Array[String]
,而是A
类型.但是,有没有一种方法可以告诉Scala将其翻译"成所需的类型呢?
Similar errors show up when I try to call Map
-specific methods on m
when foo
is a Baz
(along the lines of value keys is not a member of Qux.this.foo.A
, etc.). I understand that m
isn't really an Array[String]
-- it's of type A
. But is there a way to tell Scala to "translate" this into its desired type?
推荐答案
访问ADT中单个类型的更简单方法是使用抽象类型成员,而不是通用类型参数.
An easier way to access the individual types in your ADT is to use an abstract type member instead of a generic type parameter.
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
}
}
使用它(查看返回类型)
Using it (look at the return types)
@ Qux(Baz).m
res6: Map[String, Array[String]] = Map()
@ Qux(Bar).m
res7: Array[String] = Array()
这篇关于派生类作为类构造函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!