Scala 重写 F 有界多态中子类型的类型参数
Scala rewriting type parameter of sub type in F-bounded polymorphism
我正在尝试创建一个特性 Entity
,它强制其子类型具有 2 个状态:Transient
和 Persistent
trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState]
例如,子 class,表示 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]
}
解释一下,对于任何扩展 Entity
的 class,方法 id
只能在 class 的状态为 Persistent
时调用(即它已保存到数据库并已分配一个自动生成的 ID)。
另一方面,方法persist
只能在class为Transient
(尚未保存到数据库)时调用。方法 persist
旨在将调用者 class 的实例保存到数据库,而 return class 的 Persistent
版本。
现在,问题是 我希望 persist
的 return 类型是调用者 class 的类型。例如,如果我在 class Post[Transient]
的实例上调用 persist
,它应该 return 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] = {
???
}
}
在上面的classPost
中,我使用Eclipse的自动补全生成方法persist
的实现,发现其return类型仍然是不正确。
第二次尝试:
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 EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState] {
def id(implicit ev: State <:< Persistent): Long
def persist(implicit ev: State <:< Transient): Entity[Persistent]
}
class Post[State <: EntityState] extends Entity[State] {
override def id(implicit ev: <:<[State, Persistent]): Long = 5
override def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = new Post[Persistent]
}
// compiles
val x: Post[Persistent] = (new Post[Transient]).persist
// doesn't compile, as desired
// val y = (new Post[Persistent]).persist
我相信这就是你想要做的:
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] = {
???
}
}
更新: _: Self[State] =>
部分是 自类型注释 。它说任何混合 Entity
特征 的 class 必须 扩展 Self[State]
(不这样做会导致编译时错误)。如果我们删除这个自类型注释,我们可能会定义这样的东西,编译器不会眨眼:
abstract class User[State <: EntityState] extends Entity[State, Post] {
def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
???
}
}
请注意 User
class 如何将 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] {
^
我正在尝试创建一个特性 Entity
,它强制其子类型具有 2 个状态:Transient
和 Persistent
trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState]
例如,子 class,表示 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]
}
解释一下,对于任何扩展 Entity
的 class,方法 id
只能在 class 的状态为 Persistent
时调用(即它已保存到数据库并已分配一个自动生成的 ID)。
另一方面,方法persist
只能在class为Transient
(尚未保存到数据库)时调用。方法 persist
旨在将调用者 class 的实例保存到数据库,而 return class 的 Persistent
版本。
现在,问题是 我希望 persist
的 return 类型是调用者 class 的类型。例如,如果我在 class Post[Transient]
的实例上调用 persist
,它应该 return 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] = {
???
}
}
在上面的classPost
中,我使用Eclipse的自动补全生成方法persist
的实现,发现其return类型仍然是不正确。
第二次尝试:
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 EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState] {
def id(implicit ev: State <:< Persistent): Long
def persist(implicit ev: State <:< Transient): Entity[Persistent]
}
class Post[State <: EntityState] extends Entity[State] {
override def id(implicit ev: <:<[State, Persistent]): Long = 5
override def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = new Post[Persistent]
}
// compiles
val x: Post[Persistent] = (new Post[Transient]).persist
// doesn't compile, as desired
// val y = (new Post[Persistent]).persist
我相信这就是你想要做的:
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] = {
???
}
}
更新: _: Self[State] =>
部分是 自类型注释 。它说任何混合 Entity
特征 的 class 必须 扩展 Self[State]
(不这样做会导致编译时错误)。如果我们删除这个自类型注释,我们可能会定义这样的东西,编译器不会眨眼:
abstract class User[State <: EntityState] extends Entity[State, Post] {
def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
???
}
}
请注意 User
class 如何将 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] {
^