我之前尝试将此问题分解为更小,更简单的问题here和here,但我意识到这些问题的答案虽然在技术上是正确的,却无法帮助我理解这一特定情况。
我正在使用一个库Circumflex ORM,它允许您按如下方式定义模式:
class User extends Record[Int, User] {
val name = "name".TEXT
val age = "age".INTEGER
def relation = User
}
object User extends User with Table[Int, User]
这是因为在Record:
范围内的隐式视图abstract class Record[PK, R <: Record[PK, R]] extends Equals { this: R =>
implicit def view(x: String) = new DefinitionHelper(x, this)
...
}
class DefinitionHelper[R <: Record[_, R]](name: String, record: R) {
def TEXT = ...
def INTEGER = ...
...
}
我正在尝试引入一种名为BYTEA的TEXT等新扩展方法。所以我知道我需要自己的隐式助手类:
class DefinitionHelper[R <: Record[_, R]](name: String, record: R) {
def BYTEA = new BytesField[R](name, record)
}
现在,每当我定义新记录时,我都需要一个隐含的范围,但是 我不想每次都写一个import语句:
class User extends Record[Int, User] {
import Implicits._
...
}
我不想将此隐含介绍给任何其他范围 除了记录定义。
import Implicits._
class User extends Record[Int, User] { ... }
所以一个想法是将Record子类化(或引入一个mixin),然后定义 我的架构记录通过扩展MyRecord而不是Record(或总是 在MyMixin中混合)。
class User extends MyRecord[Int, User] { ... }
我第一次尝试:
abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, R] {
implicit def str2ddlHelper2(str: String) =
new DefinitionHelper(str, this)
}
这会产生:
illegal inheritance; self-type MyRecord[PK,R] does not conform to ru.circumflex.orm.Record[PK,R]'s selftype R
所以我尝试了:
abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, MyRecord[PK, R]] {
implicit def str2ddlHelper2(str: String) =
new DefinitionHelper(str, this)
}
但是在定义记录时我遇到了这两个问题:
class User extends MyRecord[Int, User] {
val id = "id".INTEGER
val value = "value".BYTEA // works
val value2 = new DefinitionHelper("", this) // does not work?!
...
def relation = User // another error here
}
object User extends User with Table[Int, User]
错误是:
inferred type arguments [User] do not
conform to class DefinitionHelper's type parameter bounds [R <:
ru.circumflex.orm.Record[_, R]]
type mismatch; found : User.type (with
underlying type object User) required:
ru.circumflex.orm.Relation[Int,MyRecord[Int,User]]
Note: User <:
MyRecord[Int,User] (and
User.type <:
ru.circumflex.orm.Table[Int,User]), but
trait Relation is invariant in type R. You may wish to define R as +R
instead. (SLS 4.5)
经过更多的摆弄,我发现一些有用的东西让我感到惊讶:
abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, R] { this: R =>
implicit def str2ddlHelper2(str: String) =
new DefinitionHelper(str, this)
}
我很想知道这里发生了什么,以及可能还有一些例子来帮助我更好地理解事物,这样我就不会觉得我总是“摆弄” - 直到它起作用。“
为问题标题道歉 - 不确定它是否有意义。
答案 0 :(得分:4)
您的第一个错误更简单,最终解决方案很容易解决。声明中的自我类型R=>
Record[PK, R <: Record[PK, R]] extends Equals { this: R =>
迫使Record
的每个后代确保它也是一个R(它不会使它成为R,后代必须做一些事情来成为R)。在实践中,这意味着在class X extends Record[PK, R]
中,R
必须是X
的祖先(并且还有R <: Record[PK, R]
,它应该是X
时间,但正如我们将在最后看到的,情况可能并非如此)。
此约束在MyRecord中消失,因此是您的第一个错误。您的最终解决方案再次声明约束,这就是它的结束。
你的第二个版本更复杂。 我将从第二个错误开始。
首先,Circumflex API中的一些元素未在上面说明。
Record
有一个摘要def relation: Relation[PK, R]
Table[K,R]
扩展Relation[K,R]
您可以将班级User
中的关系定义为对象User
,即Table[Int, User]
,因此为Relation[Int, User]
。
但是,您的班级User
是MyRecord[Int, User]
,但这意味着它是Record[Int, MyRecord[Int, User]]
,而不是Record[Int, User]
。 R
Record
(此处重要的一个)是MyRecord[Int, User]
,而非User
。因此,关系必须是Relation[Int, MyRecord[Int, User]]
。
即使Relation[Int, User]
是Relation[Int, MyRecord[Int, User]]
,User
也不是MyRecord[Int, User]
。一般来说,如果B
是A
,则C[B]
不是C[A]
,除非类C
通过声明为C[+X]
而声明比C[X]
。 (因此关于Relation
不变(no +)的消息,并建议+R
以便R
中的协变 })。
我对DefinitionHelper中的错误非常不确定。似乎R再次与MyRecord[Int, User]
相关。如果您明确声明为通用参数R
,则执行
new DefinitionHelper[MyRecord[Int, User]]("", this)
它应该工作(我在一个非常接近你的代码的例子上做了,但实际上并没有使用circumflex)。为什么编译器没有推断出来,我不知道。无论如何,您的User
不是Record[Int, User]
而是Record[Int, MyRecord[Int, User]]
的事实必定会导致问题。实际的解决方案要简单得多。