我试图在不使用泛型的情况下实现 F 有界多态性。我还需要使用自键入,因为我将引用 this
并期望它被键入为子类型。
trait MyTrait[T] { self: Self => // Compilation error: cannot reference 'Self'
type Self <: MyTrait[T]
def doSomethingWithSubtype() {
...
}
}
我可以使用类型参数(即泛型)很容易地实现这一点,但我想知道我是否遗漏了一些东西来进行上述编译。可以这样使用抽象类型吗?
类似问题:
这些为类似问题提供了解决方法,让我相信以上是不可能的?
F-Bound Polymorphism with Abstract Types instead of Parameter Types?
F-bounded quantification through type member instead of type parameter?
最佳答案
您可以自键入一个抽象类型,但有一个棘手的限制:它必须在您的特征之外定义,但仍然在允许实现以某种类型实现它的范围内。你可以通过将整个事情包装成一个特征来做到这一点:
trait MyTraitSystem {
type TraitImpl <: MyTrait
trait MyTrait { self: TraitImpl =>
def doSomething(t: TraitImpl): String
}
}
// with an example implementation of the trait:
object MyImpl extends MyTraitSystem {
case class TraitImpl(data: String) extends MyTrait {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
}
这相当于使用类型参数的这个版本:
trait MyTrait[T <: MyTrait[_]] { self: T =>
def doSomething(t: T): String
}
// with an example implementation of the trait:
case class TraitImpl(data: String) extends MyTrait[TraitImpl] {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
除了抽象类型版本的 import MyImpl._
之外,它们的使用方式相同:
scala> import MyImpl._
import MyImpl._
scala> val a = TraitImpl("hello")
a: MyImpl.TraitImpl = TraitImpl(hello)
scala> val b = TraitImpl("world")
b: MyImpl.TraitImpl = TraitImpl(world)
scala> b.doSomething(a)
res0: String = hello world
抽象类型版本更冗长,但它可以工作。您还需要在需要使用 TraitImpl
的任何方法/类/...中携带一个 MyTraitSystem
以提供类型:
object SomewhereElse {
def doSomethingElse(s: MyTraitSystem)(t: s.TraitImpl) =
??? // s.TraitImpl is the implementation type
}
与类型参数版本相比:
object SomewhereElse {
def doSomethingElse[T <: MyTrait[_]](t: MyTrait[T]) =
??? // T is the implementation type
}
这可能只是实现此目的的几种方法之一,但我认为没有任何一种方法可以与基于类型参数的版本的简洁性相提并论。
关于scala - 自类型可以与抽象类型一起使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17112722/