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 = [email protected]
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
}
Unforunately, вам нужно написать 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-ограниченный, т.е. trait Foo[A <: Foo]
, и сделать что-то похожее на приведенном выше примере.
BTW shadowing 'this' - не очень хорошая идея – cchantep