F-bounded多态中子类型的Scala重写类型参数

asi*_*swt 5 generics polymorphism types scala

我试图创建一个特征Entity,强制其子类型有2个状态:TransientPersistent

trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState]
Run Code Online (Sandbox Code Playgroud)

例如,一个子类,class Post[State <: EntityState] extends Entity[State]可以实例化为new Post[Persistent]new Post[Transient].

接下来,我将Entity根据以下内容添加一些可以调用的特征方法State:

trait Entity[State <: EntityState] {
    def id(implicit ev: State <:< Persistent): Long
    def persist(implicit ev: State <:< Transient): Entity[Persistent]
}
Run Code Online (Sandbox Code Playgroud)

为了解释,对于任何扩展的类,只有当类处于状态时(即它已保存到数据库并且已经分配了自动生成的id)Entity,id才能调用该方法Persistent.

另一方面,persist只有当类Transient(尚未保存到数据库)时才能调用该方法.该方法persist旨在将调用者类的实例保存到数据库并返回Persistent该类的版本.

现在,问题是我希望返回类型persist是调用者类的返回类型.例如,如果我调用persist类的实例Post[Transient],它应该返回Post[Persistent]而不是Entity[Persistent].

我四处搜寻,发现了一种叫做F-Bounded Polymorphism的东西.我正在尝试很多方法来适应它来解决我的问题,但仍然无效.这是我做的:

第一次尝试:

trait Entity[State <: EntityState, Self[_] <: Entity[State,Self]] {
    def id(implicit ev: State <:< Persistent): Long
    def persist(implicit ev: State <:< Transient): Self[Persistent]
}
Run Code Online (Sandbox Code Playgroud)

class Post[State <: EntityState] extends Entity[State, ({type ?[B] == Post[State]})#?] {

    def persist(implicit ev: <:<[State, Transient]): Post[State] = {
        ???
    }
}
Run Code Online (Sandbox Code Playgroud)

Post上面的类中,我使用Eclipse的自动完成来生成方法的实现,persist并发现它的返回类型仍然不正确.

第二次尝试:

class Post[State <: EntityState] extends Entity[State, Post] {

   def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
       ???
   }
}
Run Code Online (Sandbox Code Playgroud)

有了它,它似乎是正确的,除了它有一个编译错误:

[error] D:\playspace\myblog\app\models\post\Post.scala:14: kinds of the type arguments (State,models.post.Post) do not conform to the expected kinds of the type parameters (type State,type Self) in trait Entity.
[error] models.post.Post's type parameters do not match type Self's expected parameters:
[error] type State's bounds <: common.models.EntityState are stricter than type _'s declared bounds >: Nothing <: Any
[error] trait Post[State <: EntityState] extends Entity[State, Post] {
Run Code Online (Sandbox Code Playgroud)

Rég*_*les 3

我相信这就是您想要做的:

trait Entity[State <: EntityState, Self[S<:EntityState] <: Entity[S, Self]] {
  _: Self[State] =>

    def id(implicit ev: State <:< Persistent): Long
    def persist(implicit ev: State <:< Transient): Self[Persistent]
}


abstract class Post[State <: EntityState] extends Entity[State, Post] {
   def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
       ???
   }
}
Run Code Online (Sandbox Code Playgroud)

更新:_: Self[State] =>部分是一个自我类型注释。它表示任何混合该Entity特征的类都必须扩展Self[State](不这样做将导致编译时错误)。如果我们删除这个自类型注释,我们可能会定义类似这样的东西,并且编译器不会眨眼:

abstract class User[State <: EntityState] extends Entity[State, Post] {
   def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
       ???
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意 outUser类如何使用设置为(而不是)的类型参数Entity进行扩展。就编译器而言,这是有效的,但肯定不是您想要的。使用 self-type 注释,上面的代码将无法编译:SelfPostUser

<console>:12: error: illegal inheritance;
 self-type User[State] does not conform to Entity[State,Post]'s selftype Post[State]
           abstract class User[State <: EntityState] extends Entity[State, Post] {
                                                             ^
Run Code Online (Sandbox Code Playgroud)