【发布时间】:2014-11-24 04:34:06
【问题描述】:
假设我们有一个特征,它有一些值和一些操作。
trait Foo {
type Self <: Foo
val x: Int
def withX(x: Int): Self
}
这是使用抽象类型实现的。我们在 Self 上绑定了一个类型,可以像这样实现它:
case class Foo1(x: Int) extends Foo {
type Self = Foo1
def withX(x: Int) = copy(x = x)
}
没关系。我们可以使用该方法,我们看到类型是静态保留的。
scala> Foo1(10).withX(5)
res0: Foo1 = Foo1(5)
当我们想要一个具有特征类型而不是具体类型的操作时,问题就开始了:
object Foo {
//Error:(13, 43) type mismatch;
//found : f.Self
//required: A
// def setFive[A <: Foo](f: A): A = f.withX(5)
}
好吧,我们不能完全做到这一点,因为编译器不知道 Foo#Self 将被分配到什么类型。但我们知道它是同一类型。
当然,使用丑陋的方法也可以:
object Foo {
// Ugly type signature
def setFiveValid[A <: Foo](f: A): A#Self = f.withX(5)
// Another ugly type signature
def setFiveValid2[A <: Foo](f: A): f.Self = f.withX(5)
}
他们都没有很清楚地表达意图。
我们可以使用类型类来解决它。
case class Foo2(x: Int)
trait FooOps[A] extends Any {
def a: A
def withX(x: Int): A
}
object Foo2 {
implicit class Foo2Ops(val a: Foo2) extends AnyVal with FooOps[Foo2] {
def withX(x: Int) = a.copy(x = x)
}
}
object Foo {
// View bounds approach.
def setFiveValid3[A <% FooOps[A]](f: A): A = f.withX(5)
}
不过这还是很吵。
有没有更好的方法来实现setFive?
编辑 1
self 类型的主要问题是这样的:
Error:(24, 11) type mismatch;
found : app.models.world.WObject.WorldObjUpdate[self.Self] => app.models.world.WObject.WorldObjUpdate[self.Self]
(which expands to) app.models.game.events.Evented[(app.models.world.World, self.Self)] => app.models.game.events.Evented[(app.models.world.World, self.Self)]
required: app.models.world.WObject.WorldObjUpdate[self.Self] => app.models.game.events.Evented[(app.models.world.World, Self)]
(which expands to) app.models.game.events.Evented[(app.models.world.World, self.Self)] => app.models.game.events.Evented[(app.models.world.World, Self)]
identity
^
然后再次使用看起来很奇怪的签名和样板:
def attackReachable(
data: WObject.WorldObjUpdate[Self]
): WObject.WorldObjUpdate[data.value._2.Self]
【问题讨论】:
标签: scala typeclass traits abstract-type