2017-01-03 45 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阴影'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.typeFooImpl1在某些情况下,但是编译器无法知道的方式。您需要某种方法来捕获更精细的类型FooImpl1FooImpl2。自我类型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],并做一些类似上述例子的东西。