我想在自我类型的特征中引用Scala中自我类型注释的具体类型。我有这样的事情:
trait Foo
class FooImpl1 extends Foo
class FooImpl2 extends Foo
trait SpecialFoo {
this:Foo =>
def |+|(that:this.type):this.type // the type signature is incorrect here
}
如果我new FooImpl1 with SpecialFoo
,我希望|+|
方法要求并返回FooImpl1
(或FooImpl1
的子类型)。但是,使用上面的代码似乎需要一个SpecialFoo.this.type
,这不足为奇,但不是我想要的。
答案 0 :(得分:1)
this.type
是您拥有的SpecialFoo
个实例的单例类型。根据定义,|+|
只能自行调用。例如:
trait Spec { def |+|(that: this.type): this.type = that }
val s = new Spec {}
val s2 = new Spec {}
scala> s |+| s
res1: <refinement>.type = $anon$1@118102ee
scala> s |+| s2
<console>:14: error: type mismatch;
found : Spec
required: <refinement>.type
s |+| s2
^
在某些情况下, this.type
FooImpl1
,但编译器无法知道这一点。您需要某种方法来捕获更精细的FooImpl1
或FooImpl2
类型。自我类型this: Foo =>
只关心它是Foo
。有几种可能性,但两者都不会像你想要的那样好。
您可以参数化SpecialFoo
:
trait Foo
class FooImpl1 extends Foo
class FooImpl2 extends Foo
trait SpecialFoo[A <: Foo] { self: A =>
def |+|(that: A): A
}
val foo = new FooImpl1 with SpecialFoo[FooImpl1] {
def |+|(that: FooImpl1): FooImpl1 = that
}
不幸的是,您需要两次编写FooImpl1
,但自我类型仍会阻止您混合使用两种不同的实现。
另一种方法是在Foo
中使用类型成员。创建SpecialFoo
时,您不必两次指定实现类型,但是在创建实现时会自己绑定正确的类型。
trait Foo { type S }
class FooImpl1 extends Foo { type S = FooImpl1 }
class FooImpl2 extends Foo { type S = FooImpl2 }
trait SpecialFoo { self: Foo =>
def |+|(that: self.S): self.S
}
val foo = new FooImpl1 with SpecialFoo {
def |+|(that: FooImpl1): FooImpl1 = that
}
您还可以Foo
F-bounded,即trait Foo[A <: Foo]
,并执行类似于上述示例的操作。