[英]Scala rewriting type parameter of sub type in F-bounded polymorphism
I am trying to create a trait Entity
which enforces its sub types to have 2 states: Transient
and Persistent
我正在尝试创建一个特征Entity
,该Entity
将其子类型强制具有两种状态: Transient
和Persistent
trait EntityState
trait Transient extends EntityState
trait Persistent extends EntityState
trait Entity[State <: EntityState]
For example, a sub class, says class Post[State <: EntityState] extends Entity[State]
, can be instantiated either as new Post[Persistent]
or as new Post[Transient]
. 例如, class Post[State <: EntityState] extends Entity[State]
的子类可以实例化为new Post[Persistent]
或new Post[Transient]
。
Next, I am adding some methods to the trait Entity
that can be called depending on its State
: 接下来,我向特征Entity
添加一些方法,可以根据其State
调用它们:
trait Entity[State <: EntityState] {
def id(implicit ev: State <:< Persistent): Long
def persist(implicit ev: State <:< Transient): Entity[Persistent]
}
To explain, for any class that extends Entity
, the method id
can be called only when the class is of state Persistent
(ie it has been saved to the database and already assigned an autogenerated id). 解释一下,对于任何扩展Entity
类,仅当该类的状态为Persistent
(即已保存到数据库并已分配了自动生成的ID)时,才可以调用方法id
。
On the other hand, the method persist
can be called only when the class is Transient
(not yet saved to the database). 另一方面,仅当类为Transient
(尚未保存到数据库)时才可以调用persist
方法。 The method persist
is meant to save an instance of the caller class to the database and return the Persistent
version of the class. 方法persist
是用于将调用者类的实例保存到数据库中并返回该类的Persistent
版本。
Now, the problem is I would like that the return type of persist
be that of the caller class . 现在,问题是我希望persist
的返回类型是调用方类的返回类型 。 For example, if I call persist
on an instance of class Post[Transient]
, it should return Post[Persistent]
instead of Entity[Persistent]
. 例如,如果我在类Post[Transient]
的实例上调用persist
,则它应返回Post[Persistent]
而不是Entity[Persistent]
。
I searched around and found something called F-Bounded Polymorphism . 我四处搜寻,发现了一个叫做F界多态的东西。 I am trying many ways to adapt it to solve my problem but still not works. 我正在尝试多种方法来适应它来解决我的问题,但仍然行不通。 Here is what I did: 这是我所做的:
First try: 第一次尝试:
trait Entity[State <: EntityState, Self[_] <: Entity[State,Self]] {
def id(implicit ev: State <:< Persistent): Long
def persist(implicit ev: State <:< Transient): Self[Persistent]
}
and 和
class Post[State <: EntityState] extends Entity[State, ({type λ[B] == Post[State]})#λ] {
def persist(implicit ev: <:<[State, Transient]): Post[State] = {
???
}
}
In the class Post
above, I use auto-completion of Eclipse to generate the implementation of the method persist
and found that its return type is still incorrect. 在上面的Post
类中,我使用Eclipse的自动完成功能来生成persist
方法的实现,并发现其返回类型仍然不正确。
Second try: 第二次尝试:
class Post[State <: EntityState] extends Entity[State, Post] {
def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
???
}
}
with this, it seems correct, except it has a compilation error: 这样做似乎是正确的,除了它有一个编译错误:
[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] {
I believe this is what you were trying to do: 我相信这是您想要做的:
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] = {
???
}
}
UPDATE: The _: Self[State] =>
part is a self-type annotation . 更新: _: Self[State] =>
部分是一个自类型注释 。 It says that any class that mixes the Entity
trait must extend Self[State]
(not doing so would lead to a compile-time error). 它说任何混合了Entity
特性的类都必须扩展Self[State]
(不这样做会导致编译时错误)。 If we remove this self-type annotation, we might define something like this and the compiler would not blink an eye: 如果删除此自类型注释,则可能会定义如下内容,并且编译器不会眨眼:
abstract class User[State <: EntityState] extends Entity[State, Post] {
def persist(implicit ev: <:<[State, Transient]): Post[Persistent] = {
???
}
}
Note how out User
class extends Entity
with the Self
type parameter set to Post
(instead of User
). 请注意User
类如何通过将Self
类型参数设置为Post
(而不是User
)扩展Entity
。 This is valid as far as the compiler is concerned, but was certainly not what you had in mind. 就编译器而言,这是有效的,但肯定不是您所想到的。 With the self-type annotation, the above would not compile: 使用自类型注释时,以上内容将无法编译:
<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] {
^
Why doesn't plain old ad-hoc polymorphism satisfy you here? 为什么普通的旧式临时多态性在这里不满意? Eg, this compiles. 例如,此编译。
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.