问题描述
我希望能够在外部嵌套泛型类的函数中传递相同类型的参数,但也有一个多态的内部泛型类 - 允许我为 InnerShell 和使用抽象基类/特征外壳两者。这在 Scala 中甚至可能吗?
class OuterShellClass[Generic] {
def doSomething(param : OuterShellClass[Generic]) : OuterShellClass[Generic] = this;
}
abstract class InnerShellClass[Type] {
}
class InnerShellSubclass[Type] extends InnerShellClass[Type]{
}
class wrapper{
val obj : OuterShellClass[InnerShellClass[String]] = new OuterShellClass[InnerShellSubclass[String]];
}
如果 OuterShellClass 是不变量,则会出现错误:
Note: InnerShellSubclass[String] <: InnerShellClass[String],but class OuterShellClass is invariant in type Generic
如果 OuterShellClass 是协变的,我会收到错误:
covariant type Generic occurs in contravariant position in type OuterShellClass[Generic] of value param
更新:
在我考虑的时候,这个快速的 hack 会奏效 - 请告诉我有更好的解决方案。由于 OuterShellClass 函数内的泛型实际上独立于类创建时的泛型定义 - 不一定是同一个类 - 我不能保证在运行时兼容类。将这些特定函数移至全局函数类,以便我可以收回保证并获得解决方案。我真的需要像这样分割我的课程吗?有没有更好的解决方案?
class OuterShellClass[+Generic] {
}
class Helper {
def doSomething[T] (param1: OuterShellClass[T],param2: OuterShellClass[T]) = param1;
}
abstract class InnerShellClass[Type] {
}
class InnerShellSubclass[Type] extends InnerShellClass[Type]{
}
class wrapper{
val obj : OuterShellClass[InnerShellClass[String]] = new OuterShellClass[InnerShellSubclass[String]];
}
解决方法
代码第一 - 之后解释。
class OuterShellClass[+Generic] {
}
object OuterShellClass {
def doSomething[T] (param1: OuterShellClass[T],param2: OuterShellClass[T]): OuterShellClass[T] = param1
}
abstract class InnerShellClass[Type] {
}
class InnerShellSubclass[Type] extends InnerShellClass[Type]{
}
class wrapper{
val obj : OuterShellClass[InnerShellClass[String]] = new OuterShellClass[InnerShellSubclass[String]]
val result : OuterShellClass[InnerShellClass[String]] = OuterShellClass.doSomething(obj,new OuterShellClass[InnerShellSubclass[String]])
}
据我所知,Scala 对多态性有独特的看法,这与要求数组的所有元素属于完全相同的类有关(有警告)。结果,那些来自其他语言(特别是 Java)的人发现多态性打破了 Scala 泛型内部的预期,即使在使用协变和逆变时也是如此。在这个例子中, doSomething(ISubClass1 a,ISubClass2 b) 是一个编译错误。在多态下,这样做是合法的,但在 Scala 泛型中是不允许的。 第一个版本:
class OuterShellClass[+Generic] {
def doSomething(param: OuterShellClass[Generic]): OuterShellClass[Generic] = this
}
在这种情况下,不需要 param 的类与周围对象的类相同,从而导致需要“逆变”的错误,这在这种情况下是不可能满足的。我发现解决此问题的唯一方法是引用泛型类型(在本例中为泛型)并将它们移动到可以显式建立这些限制的伴随对象中的函数的移位方法 - 该对象没有泛型,而泛型在该函数不是协方差。这符合 Scala 要求,即容器只有一类对象(有警告),同时仍然允许在内部泛型类中使用一些多态。
愿你的 Scala 泛型之旅比我的更顺利...