简体   繁体   English

了解Scala中自我类型和类型界限之间的相互作用

[英]Understanding the interaction in Scala between self-types and type bounds

I previously tried breaking this problem down into smaller, simpler problems here and here , but I realized that answers to those, while technically correct, were not helping me understand this particular case. 我以前曾尝试在这里这里将这个问题分解为更小,更简单的问题,但是我意识到,这些问题的答案虽然在技术上是正确的,但并不能帮助我理解这种特殊情况。

I'm using a library, Circumflex ORM , that lets you define schemas as follows: 我正在使用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]

This works because of an implicit view that's in-scope within Record: 之所以能够成功,是因为在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 = ...
  ...
}

I'm trying to introduce a new extension method alongside TEXT, etc. called BYTEA. 我正在尝试引入一种新的扩展方法以及TEXT等,称为BYTEA。 So I know I need my own implicit helper class: 所以我知道我需要自己的隐式帮助器类:

class DefinitionHelper[R <: Record[_, R]](name: String, record: R) {
 def BYTEA = new BytesField[R](name, record)
}

Now I need an implicit in scope whenever I'm defining new records, but I don't want to write an import statement every time: 现在,每当定义新记录时,我就需要一个隐式范围,但是我不想每次都写一个import语句:

class User extends Record[Int, User] {
 import Implicits._
 ...
}

And I don't want to introduce this implicit to any other scopes besides the record definitions. 而且我不想将此隐式引入到除记录定义之外的任何其他范围。

import Implicits._
class User extends Record[Int, User] { ... }

So one idea is to subclass Record (or introduce a mixin), then define my schema records by extending MyRecord instead of Record (or always mixing in MyMixin). 因此,一个想法是将Record子类化(或引入mixin),然后通过扩展MyRecord而不是Record来定义我的模式记录(或始终在MyMixin中进行混合)。

class User extends MyRecord[Int, User] { ... }

I first tried: 我首先尝试:

abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, R] {
  implicit def str2ddlHelper2(str: String) =
    new DefinitionHelper(str, this)
}

This produces: 这将产生:

illegal inheritance;  self-type MyRecord[PK,R] does not conform to ru.circumflex.orm.Record[PK,R]'s selftype R

So instead I tried: 因此,我尝试了:

abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, MyRecord[PK, R]] {
 implicit def str2ddlHelper2(str: String) =
   new DefinitionHelper(str, this)
}

But then I get these two issues when defining a record: 但是随后在定义记录时遇到了两个问题:

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]

The errors are: 错误是:

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)

After more fiddling, I surprised myself by finding something that worked: 经过更多的摆弄之后,我惊讶地发现了一些有效的方法:

abstract class MyRecord[PK, R <: MyRecord[PK, R]]
extends Record[PK, R] { this: R =>
  implicit def str2ddlHelper2(str: String) =
    new DefinitionHelper(str, this)
}

I'm curious to understand what just happened here, as well as perhaps some more examples to help me wrap my head around things better so that I don't feel like I'm always "fiddling-until-it-works." 我很好奇要理解这里发生的事情,也许还有更多的例子来帮助我更好地了解事情,以免我总是觉得自己“摆弄直到工作”。

Apologies for the question title - not sure it makes any sense. 对问题标题表示歉意-不确定是否有意义。

Your first error is the simpler one, and easily solved by your final solution. 您的第一个错误是比较简单的错误,可以通过最终解决方案轻松解决。 The self type R=> in the declaration 声明中的自身类型R=>

Record[PK, R <: Record[PK, R]] extends Equals { this: R =>

forces every descendant of Record to ensure that it will be an R too (it does not make it an R, the descendant will have to do something to be an R). 强制Record每个后代确保它也将是R(它不会使其成为R,它的后代将必须做一些事情才能成为R)。 In practice, that means that in class X extends Record[PK, R] , R must be an ancestor of X (and as there is also R <: Record[PK, R] , it should be X most of the time, but as we will see at the end, this may not be the case). 实际上,这意味着在class X extends Record[PK, R]R必须是X的祖先(而且还有R <: Record[PK, R] ,大多数情况下它应该是X ,但是正如我们将在最后看到的,情况可能并非如此。

This constraint disappears in MyRecord, hence your first error. 该约束在MyRecord中消失,因此是您的第一个错误。 Your final solution states the constraint again and that's the end of it. 您的最终解决方案再次说明了约束,到此为止。


Your second version is more complicated. 您的第二个版本更加复杂。 I'll start with the second error. 我将从第二个错误开始。

first, some elements from the Circumflex API not stated above. 首先,来自Circumflex API的某些元素未在上面说明。

  • Record has an abstract def relation: Relation[PK, R] Record具有抽象的def relation: Relation[PK, R]
  • Table[K,R] extends Relation[K,R] Table[K,R]扩展Relation[K,R]

You define relation in the class User as the object User , which is a Table[Int, User] , hence a Relation[Int, User] . 您在类User中将关系定义为对象User ,它是Table[Int, User] ,因此是Relation[Int, User]

However, your class User is a MyRecord[Int, User] , but that means it is a Record[Int, MyRecord[Int, User]] , not a Record[Int, User] . 但是,您的类UserMyRecord[Int, User] ,但这意味着它是Record[Int, MyRecord[Int, User]] ,而不是Record[Int, User] The R of Record (the one that matters here) is MyRecord[Int, User] , not User . RecordR (在这里很重要)是MyRecord[Int, User] ,而不是User relation must thus be Relation[Int, MyRecord[Int, User]] . 因此, Relation[Int, MyRecord[Int, User]]必须是Relation[Int, MyRecord[Int, User]]

A Relation[Int, User] is not a Relation[Int, MyRecord[Int, User]] , even when User is a MyRecord[Int, User] . 即使UserMyRecord[Int, User] Relation[Int, User]也不是Relation[Int, MyRecord[Int, User]] MyRecord[Int, User] In general, if B is an A , C[B] is not a C[A] , except if class C states so by being declared C[+X] rather than C[X] . 通常,如果BA ,则C[B]不是C[A] ,除非类C通过声明为C[+X]而不是C[X] (hence the message about Relation being invariant (no +), and suggesting a +R so that it would be covariant in R ). (因此,有关“ Relation不变 (否+)的信息,并建议一个+R以便它在R协变 )。

I'm really less sure about the error in DefinitionHelper. 我真的不太确定DefinitionHelper中的错误。 It seems related to the R being MyRecord[Int, User] again. 似乎与R再次是MyRecord[Int, User] If you explicitly state that as the generic parameter R , doing 如果您明确地将其声明为通用参数R ,那么

new DefinitionHelper[MyRecord[Int, User]]("", this) 

it should work (I did it on an example quite close to your code, but not actually using circumflex). 它应该可以工作(我在一个非常接近您的代码的示例中完成了此操作,但实际上并未使用circumflex)。 Why the compiler does not infer that, I do not know. 我不知道为什么编译器不推断这一点。 Anyway, the fact that your User is not a Record[Int, User] but Record[Int, MyRecord[Int, User]] is bound to cause problems. 无论如何,您的User不是Record[Int, User]而是Record[Int, MyRecord[Int, User]]必然会引起问题。 The actual solution is much simpler. 实际的解决方案要简单得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM