Scala得到了自我类型的具体类型

时间:2017-01-03 19:57:37

标签: scala types self-type

我想在自我类型的特征中引用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,这不足为奇,但不是我想要的。

1 个答案:

答案 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,但编译器无法知道这一点。您需要某种方法来捕获更精细的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
}

不幸的是,您需要两次编写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],并执行类似于上述示例的操作。