我有一個Accessor類檢索項目。它也可以將一個Item作爲參數,並從數據庫中返回該Item的最新版本。當它創建一個Item時,它將自身作爲參數傳遞給Item。如何使用scala的單例對象類型來要求通過構造函數的某個參數創建一個對象?
我希望編譯器靜態地要求Accessor實例只接受由它自己創建的項目。這是由How to use Scala's singleton-object types?涵蓋但是我也希望一個Item實例能夠將自己作爲參數傳遞給它自己的Accessor以檢索它自己的最新版本。
這樣做的困難是,在項目類定義的類型參數,像這樣
class Item[A <: Accessor](acc: A)
不能引用ACC本身的類型。從項目acc.type <: A <: Accessor
所以this
項目Item[A]
的角度,不是Item[acc.type]
。因此,這並不工作:
class Item[A <: Accessor](acc: A) {
acc.accept(this) // Type Mismatch: found Item[A], required Item[Item.this.acc.type]
}
class Accessor {
def make() = new Item[this.type](this)
def accept(item: Item[this.type]) = "accepted"
}
然後我嘗試這樣做:
object A1 extends Accessor[A1.type](A1) // illegal cyclic reference involving object A1
class Item[+A <: Accessor[A]](acc: A) {
acc.accept(this)
A1.accept(this) // Compile error (good)
}
class Accessor[+A <: Accessor[A]](me: => A) {
def make = new Item[A](me)
def accept(item: Item[A]) = "accepted"
}
哪裏的問題實際上是創建訪問器的一個實例。
我試圖上述這被證明是相同的基本困境的混亂化身的變化:
object A1 extends Accessor {
type A = A1.type
def me = A1
}
class Item[+AA <: Accessor](acc: AA {type A = AA}) {
acc.accept(this)
A1.accept(this) // Compile error (good)
}
class Accessor {
type A <: Accessor
def me: A // can't do {type A = A} because its a cyclic error again
def make = new Item[A](me) // Type Mismatch: found this.A, required this.A {type A = Accessor.this.A}
def accept(item: Item[A]) = "accepted"
}
最後我試圖使所述A
類型參數逆變使得項目[A]是一種亞型項目[acc.type],並將被acc收錄。
val a1 = new Accessor
val a2 = new Accessor
val item1 = a1.make
val item2 = a2.make
val itemA = new Item[Accessor](a2)
val item12 = new Item[A1.type](a2) // compile error (good)
a1.accept(itemA) // no compile error (bad), but I can prevent creation of Item[Accessor]s
a1.accept(item2) // compile error (good)
class Item[-A <: Accessor](acc: A) {
acc.accept(this)
val acc2 = new Accessor
acc2.accept(this) // compile error (good)
// here Item[Accessor] <: Item[A] <: Item[acc.type]
// and Item[Accessor] <: Item[acc2.type]
// but Item[A] is not necessarily <: Item[acc2.type]
}
class Accessor {
def make() = new Item[this.type](this)
def accept(item: Item[this.type]) = "accepted"
}
這最接近我嘗試過的任何東西的工作。唯一的問題是,因爲我不能做到這一點充塞了我的對象層次:
class ImmutableAccessor extends Accessor
class ImmutableItem[-A <: ImmutableAccessor](acc: A) extends Item[A] // fails due to contravariance in A
如果只是有一些方法來指定一個類型參數必須是單式。因此,例如,你可以說(我在這裏發明了記號)
class Item[A:type <: Accessor](acc: A)
而且A
那麼將是acc
的單類型,我們會笑着說。
「與單身」的東西看起來像我希望的功能。它應該允許像'class Item [A <:Accessor with Singleton](acc:A)'這樣的語句確保A與acc.type的類型完全相同,從而允許Item將自身傳遞給它的Accessor。不幸的是,編譯器似乎沒有認識到這個邏輯,仍然認爲A>:acc.type。 –