2011-07-27 70 views
2

我以前試圖將這個問題分解成更小,更簡單的問題herehere,但我意識到這些技術上正確的答案並沒有幫助我理解這個特定案件。瞭解在自我類型和類型邊界之間的Scala中的交互

我使用圖書館,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] { ... } 

那麼一個想法是繼承記錄(或引進一個mixin),然後通過延長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) 
} 

但隨後定義,當我得到了這兩個問題記錄:

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

您的第一個錯誤是更簡單的錯誤,並且可以通過最終解決方案輕鬆解決。在聲明中自我型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]Record(這裏重要的一個)的RMyRecord[Int, User],而不是User。關係必須是Relation[Int, MyRecord[Int, User]]

A Relation[Int, User]不是Relation[Int, MyRecord[Int, User]],即使UserMyRecord[Int, User]。通常,如果BA,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) 

它應該工作(我做這件事是非常接近你的代碼,但實際上並沒有使用抑揚的例子)。爲什麼編譯器不會推斷,我不知道。無論如何,你的User不是Record[Int, User],但Record[Int, MyRecord[Int, User]]必然會造成問題。實際的解決方案要簡單得多。