Scala中的F-Bounded多态返回类型?

时间:2015-01-11 18:47:19

标签: scala generics polymorphism

我疯狂地试图让F-Bounded Polymorphism按照我想要的方式在Scala中工作。

以下代码无法编译:

object TestTypeBounds {

   trait Upper[T <: Upper[T]] {
      def map() : T
   }

   class Impl extends Upper[Impl] {
      def map() : Impl = this
   }

  type Arr = Upper[T] forSome {type T <: Upper[T]}

  def testBounds() {

     // Though any is specified as the type parameter, the definition of Upper specifies
     // an upper bound of Upper
     val upper: Upper[_] = new Impl()

     // This must 'logically' be an Upper, but the compiler thinks it's an Any
     val mapped = upper.map()

     // This line will fail!
     mapped.map().map().map()
  }

  def main(args: Array[String]): Unit = {
     testBounds()
  }
}

这里的问题是编译器抱怨映射的类型是Any,因此它没有方法映射。我不清楚为什么编译器不指定映射类型Upper,因为这实际上是Upper参数类型的上限类型,即使在此实例中指定了任何一个。

请注意,用别名Arr替换“val upper ...:”的类型会起作用,因为现在Scala可以看到该类型是递归的并且始终是Upper。不幸的是,这种方法对我来说也不起作用,因为我正在实现一个Java函数,它将Upper [_]参数传递给函数,然后它们会遇到上述问题。编译器也不接受将这些函数重写为具有“Arr”参数的代码,即别名在该场景中不起作用。

编辑:最后一段不完全正确,请参阅下面的答案

3 个答案:

答案 0 :(得分:2)

正如@Rado Buransky指出的那样,你不能只使用下划线省略类型构造函数参数。以下作品例如:

def testBounds[T <: Upper[T]](make: => T): Unit = {
  val upper: T = make
  val mapped = upper.map()
  mapped.map().map().map()
}

testBounds(new Impl)

此外,使用存在类型:

def testBounds: Unit = {
  val upper: Upper[T] forSome { type T <: Upper[T] } = new Impl
  val mapped = upper.map()
  mapped.map().map().map()
}

答案 1 :(得分:1)

我对此的看法是你不应该使用下划线&#34; _&#34;。它告诉编译器你不关心类型参数。但你做了。我知道有上限,但可能有一个优化使编译器真的不在乎。

对我来说,只是一个提示,如果没有任何效果,总会有asInstanceOf[T]方法。也许这有助于你:

def giveMeUpper[T <: Upper[T]] = (new Impl).asInstanceOf[Upper[T]]

...

val upper = giveMeUpper[Impl]

答案 2 :(得分:0)

就问题的'纯'Scala部分而言,0__是正确的,我接受了他的回答。

关于Java部分:事实证明,如果Java函数返回Upper,并且上层接口在Java中定义,与上面的Scala实现等效,那么编译器确实正确地为它分配了类型Upper [_ $ 2] forSome {type $ 2&lt;:Upper [ $ 2]} - 即它正确地互操作。我遇到的最后一个问题实际上是由Scala中定义的隐式函数引起的,它仍返回Upper [_]。 Mea Culpa。

相关问题