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

我正在尝试创建一个特性实体,它强制其子类型有2种状态:瞬态和持久

trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState]

例如,一个子类,类Post [State&lt ;:EntityState]扩展Entity [State],可以实例化为新Post [Persistent]或新Post [Transient].

接下来,我将一些方法添加到特性实体,可以根据其状态调用它:

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

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

另一方面,只有当类是Transient(尚未保存到数据库)时,才能调用方法persist.方法持久化意味着将调用者类的实例保存到数据库并返回该类的持久版本.

现在,问题是我希望persist的返回类型是调用者类的返回类型.例如,如果我在类Post [Transient]的实例上调用persist,它应该返回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]
}

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

    def persist(implicit ev: <:<[State,Transient]): Post[State] = {
        ???
    }
}

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

第二次尝试:

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

   def persist(implicit ev: <:<[State,Transient]): Post[Persistent] = {
       ???
   }
}

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

[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] {

解决方法

我相信这是你想要做的:

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] = {
       ???
   }
}

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

abstract class User[State <: EntityState] extends Entity[State,Transient]): Post[Persistent] = {
       ???
   }
}

注意User类如何在Self类型参数设置为Post(而不是User)的情况下扩展Entity.就编译器而言,这是有效的,但肯定不是你想到的.
使用自我类型注释,上面不会编译:

<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] {
                                                             ^

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...