【问题标题】:F-Bounded Polymorphic return types in Scala?Scala中的F有界多态返回类型?
【发布时间】:2015-03-09 13:20:07
【问题描述】:

试图让 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。不幸的是,这种方法对我也不起作用,因为我正在实现一个将 Upper[_] 参数传递给函数的 Java 库,然后这些会遇到上述问题。编译器也不接受这些函数被覆盖为具有“Arr”参数的代码,即别名在这种情况下不起作用。

编辑:最后一段并不完全正确,请看下面我的回答

【问题讨论】:

    标签: scala generics polymorphism


    【解决方案1】:

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

    【讨论】:

    • 感谢 0__,存在类型方法确实是 Scala 的做法。
    【解决方案2】:

    我的观点是你不应该使用下划线“_”。它告诉编译器你不关心类型参数。但你做了。我知道有上限,但可能有一个优化让编译器真的不在乎。

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

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

    ...

    val upper = giveMeUpper[Impl]
    

    【讨论】:

    • 我不能接受你的第一点。下划线告诉编译器我不关心提供关于类型参数的任何附加信息,但肯定应该考虑现有信息,包括上限。否则,编译器优化会抵消语言特性,上限纯粹是对可以创建哪些特定实例以及可以在实现中使用哪些函数的限制。
    • 我明白你的意思,我很想听到一些真实的解释:groups.google.com/forum/#!topic/scala-language/OiFmOCV8pu8
    • 感谢您代表我所做的努力!我还限定了我之前的分歧:我坚持我之前对我想说的东西的断言,因此期望会发生,但是你的断言是正确的,编译器认为它意味着它可以完全忽略这种类型(在我的意见不是理想的行为)。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 1970-01-01
      • 2018-05-20
      • 1970-01-01
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 2015-06-03
      • 1970-01-01
      相关资源
      最近更新 更多