scala:使用concretised类型覆盖泛型,存在类型的值

时间:2015-05-17 14:57:52

标签: scala generics existential-type

我有一个通用特征MappingPath,关于它的类型参数是不变的:

trait MappingPath[X<:AnyMapping, Y<:AnyMapping]

以及它的工厂界面:

trait Pathfinder[X, Y] {
    def apply(fun :X=>Y) :MappingPath[_<:AnyMapping,_<:AnyMapping]
    def get(fun :X=>Y) :Option[MappingPath[_<:AnyMapping, _<:AnyMapping]]
}

我启动了一个适用于单个映射的框架实现:

class MappingPathfinder[M<:AnyMapping, X, Y] extends Pathfinder[X, Y] {
   override def apply(fun :X=>Y) :MappingPath[M, _<:AnyMapping] = ???
   override def get(fun :X=>Y) :Option[MappingPath[M, _<:AnyMapping]] = ???
}

产生编译错误,抱怨MappingPathfinder.apply无法覆盖任何内容并且未实现Pathfinder.apply。有趣的是,在M的返回类型中用_<:AnyMapping替换apply会使其编译,并且不会对类似get方法提出任何投诉。

发生了什么事?我使用scala 2.11.5。

编辑: 我能够通过添加明确的存在性注释来解决我的问题:

//Pathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A<:AnyMapping; type B<:AnyMapping }

//MappingPathfinder
def apply(fun :X=>Y) :MappingPath[A, B] forSome { type A>:M<:M; type B<:AnyMapping }

似乎有用,即 我能做到:

(p :MappingPath[_<:AnyMapping, M]) ++ mappingPathfinder(f),

其中++要求路径以与this完全相同的类型开头。它看起来有点傻,但肯定令人困惑。

1 个答案:

答案 0 :(得分:2)

不是答案,但您的用例可以简化为:

trait Higher[U]

trait Super {
  def foo: Higher[_]
}

trait Sub[M] {
  override def foo: Higher[M]  // error: method foo overrides nothing
}

我会使用类型成员而不是存在类型:

trait Super {
  type U
  def foo: Higher[U]
}

trait Sub[M] {
  type U = M
}

我认为不同之处在于,在存在类型的情况下,您只指定返回的类型参数具有某个上限,但不一定是它始终相同的类型;而在我的第二个示例中,type U表示最终将一个特定类型,并且您只能优化特定类型。您可以使上限更精确:

trait Upper

trait A {
  type U <: Upper  
}

trait Specific extends Upper

trait B extends A {
  type U <: Specific   // type is "overridden"
}

如果有可能,我会避免存在类型,你的情况似乎非常适合这种避免。大多数情况下,只有Java互操作才需要存在类型。