我有一个检索项目的访问器类。它还可以将 Item 作为参数并从数据库中返回该 Item 的最新版本。当它创建一个 Item 时,它会将自己作为参数传递给 Item。
我希望编译器静态地要求 Accessor 实例只接受它自己创建的项目。如何使用 Scala 的单例对象类型?但是我也希望一个 Item 实例能够将自己作为参数传递给它自己的 Accessor 以检索其自身的最新版本。
这样做的困难在于 Item 类定义中的类型参数像这样
class Item[A <: Accessor](acc: A)
不能引用 acc 本身的类型。从 Item 的角度来看,acc.type <: A <: Accessor
在this
Item 中,它是一个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
类型参数逆变,以便 Item[A] 是 Item[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
我们会笑。