Scala 中的 F 有界多态返回类型



我快要疯了,试图让 F 界多态性在 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 参数类型的类型上限,即使在此实例中指定了任何类型。

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

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

正如@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()
}

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

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

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

val upper = giveMeUpper[Impl]

就问题的"纯"Scala部分而言,0__是正确的,我已经接受了他的答案。

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

最新更新