2

私は以前、この問題をより小さく単純な問題に分解しようとしました技術的には正しいものの、この特定のケースを理解するのに役立たないことに気付きました。

次のようにスキーマを定義できるライブラリ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]

これは、レコード内のスコープ内にある暗黙的なビューのために機能します。

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] { ... }

したがって、1 つのアイデアは、Record をサブクラス化 (または mixin を導入) し、Record の代わりに MyRecord を拡張してスキーマ レコードを定義する (または常に 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)
}

しかし、レコードを定義するときに次の 2 つの問題が発生します。

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)
}

ここで何が起こったのかを理解したいと思っています.

質問のタイトルについてお詫び申し上げます - それが意味をなさないかどうかはわかりません。

4

1 に答える 1

4

最初のエラーはより単純なものであり、最終的な解決策によって簡単に解決されます。R=>宣言の自己型

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

のすべての子孫に、それも R になるように強制Recordします (R にするわけではありません。子孫は R になるために何かをしなければなりません)。実際には、これは inが の祖先でなければならないことclass X extends Record[PK, R]を意味します(また、 も存在するため、ほとんどの場合はそうなるはずですが、最後に説明するように、そうではない可能性があります)。RXR <: Record[PK, R]X

この制約は MyRecord では消えているため、最初のエラーです。あなたの最終的な解決策は、制約を再度述べており、それで終わりです。


2 番目のバージョンはより複雑です。2 番目のエラーから始めます。

最初に、上記に記載されていない Circumflex API のいくつかの要素。

  • Recordアブストラクトがありますdef relation: Relation[PK, R]
  • Table[K,R]伸びるRelation[K,R]

クラスで関係をUserobject として定義しますUser。これは aTable[Int, User]であり、したがって aRelation[Int, User]です。

ただし、クラスUserは ですが、それはではなくMyRecord[Int, User]であることを意味します。の(ここで重要なもの) はであり、 ではありません。したがって、関係は でなければなりません。Record[Int, MyRecord[Int, User]]Record[Int, User]RRecordMyRecord[Int, User]UserRelation[Int, MyRecord[Int, User]]

がであっても、AはRelation[Int, User]ではありません。一般に、が である場合、 はではありません。ただし、 クラスがではなく宣言されることによってそのように述べている場合を除きます。(したがって、不変(+なし)であり、 で共変になるように a を提案するというメッセージです)。 Relation[Int, MyRecord[Int, User]]UserMyRecord[Int, User]BAC[B]C[A]CC[+X]C[X]Relation+RR

DefinitionHelper のエラーについてはよくわかりません。RがMyRecord[Int, User] 再び存在することに関連しているようです。それをジェネリック パラメータとして明示的に指定すると、次のようになりますR

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

それはうまくいくはずです(私はあなたのコードに非常に近い例でそれを行いましたが、実際にはサーカムフレックスを使用していません)。なぜコンパイラがそれを推測しないのか、私にはわかりません。とにかく、あなたがそうではないという事実は、問題Userを引き起こすに違いありません。実際の解決策はもっと簡単です。Record[Int, User]Record[Int, MyRecord[Int, User]]

于 2011-07-27T20:39:00.197 に答える