2017-01-03 3 views
1

Я хотел бы получить ссылку на конкретный тип аннотации самонастройки в Scala в пределах типизированной черты. У меня есть что-то вроде этого: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

BTW shadowing 'this' - не очень хорошая идея – cchantep

ответ

0

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], и сделать что-то похожее на приведенном выше примере.

 Смежные вопросы

  • Нет связанных вопросов^_^