【发布时间】:2012-10-21 23:28:37
【问题描述】:
我有一个检索项目的访问器类。它还可以将 Item 作为参数并从数据库中返回该 Item 的最新版本。当它创建一个 Item 时,它会将自己作为参数传递给 Item。
我希望编译器静态地要求 Accessor 实例只接受它自己创建的项目。 How to use Scala's singleton-object types? 涵盖了这一点,但是我还希望 Item 实例能够将自身作为参数传递给它自己的 Accessor 以检索其自身的最新版本。
这样做的困难在于Item类定义中的类型参数像这样
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"
}
问题实际上出在创建 Accessor 的实例。
我在上面尝试了一种变体,结果证明这是相同基本困境的更混乱化身:
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 的单例类型,我们会笑的。
【问题讨论】:
标签: scala