Scala 中的 F-Bounded Polymorphic return 类型?
F-Bounded Polymorphic return types in Scala?
我要疯狂地尝试在 Scala 中使 F 有界多态性按我想要的方式工作。
以下代码将无法编译:
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" 个参数的代码,即别名在那种情况下不起作用。
编辑:最后一段不完全正确,请看下面我的回答
我对此的看法是你不应该使用下划线“_”。它告诉编译器您不关心类型参数。但你做了。我知道有上限,但可能有一个优化让编译器真的不在乎。
只是一个提示,有时候,对我来说,如果没有任何效果,总是有 asInstanceOf[T]
方法。也许这对你有帮助:
def giveMeUpper[T <: Upper[T]] = (new Impl).asInstanceOf[Upper[T]]
...
val upper = giveMeUpper[Impl]
正如@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()
}
就问题的 'pure' Scala 部分而言,0__ 是正确的,我接受了他的回答。
关于Java部分:原来如果一个Java函数returnsUpper和Upper接口定义在Java等同于上面的Scala实现,那么编译器实际上确实正确地为它分配了类型 Upper[_$2] forSome {type $2 <: Upper[$2]} - 即它正确地互操作。我遇到的最后一个问题实际上是由 Scala 中定义的仍返回 Upper[_] 的隐式函数引起的。我认罪。
我要疯狂地尝试在 Scala 中使 F 有界多态性按我想要的方式工作。
以下代码将无法编译:
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" 个参数的代码,即别名在那种情况下不起作用。
编辑:最后一段不完全正确,请看下面我的回答
我对此的看法是你不应该使用下划线“_”。它告诉编译器您不关心类型参数。但你做了。我知道有上限,但可能有一个优化让编译器真的不在乎。
只是一个提示,有时候,对我来说,如果没有任何效果,总是有 asInstanceOf[T]
方法。也许这对你有帮助:
def giveMeUpper[T <: Upper[T]] = (new Impl).asInstanceOf[Upper[T]]
...
val upper = giveMeUpper[Impl]
正如@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()
}
就问题的 'pure' Scala 部分而言,0__ 是正确的,我接受了他的回答。
关于Java部分:原来如果一个Java函数returnsUpper和Upper接口定义在Java等同于上面的Scala实现,那么编译器实际上确实正确地为它分配了类型 Upper[_$2] forSome {type $2 <: Upper[$2]} - 即它正确地互操作。我遇到的最后一个问题实际上是由 Scala 中定义的仍返回 Upper[_] 的隐式函数引起的。我认罪。