Scala递归类型

时间:2015-05-05 15:10:54

标签: scala types

我只是试图了解Scala的类型系统。我偶然发现了一个看起来像这样的代码:

trait A extends Something {
  type X <: XLike

  trait XLike { this: X =>
    ....
    ....
  }
}

这是什么意思?在哪种情况下我想要像这样编码?我知道我是嵌套类型,但嵌套类型的优点是什么,并使用它来引用嵌套类型?

1 个答案:

答案 0 :(得分:6)

A#XLike特征不能混合在A内的任何位置:

val a = new A {}; import a._

scala> class KK extends XLike
<console>:21: error: illegal inheritance;
 self-type KK does not conform to a.XLike's selftype a.X
       class KK extends XLike
                        ^

它可以在A实现中混合使用:

trait B extends A {
    type X = XImpl      
    trait XImpl extends XLike { this: X => }
}

val b = new B {}; import b._

scala> class KK extends XImpl
defined class KK

甚至:

trait B extends A {type X = XLike}

val b = new B {}; import b._

scala> class KK extends XLike
defined class KK

因此,它允许您选择混合使用哪个特征:

trait B extends A {
  type X = XImpl1      
  trait XImpl1 extends XLike { this: X => }
  trait XImpl2 extends XLike { this: X => }
}

val b = new B {}; import b._

scala> class ZZ extends XImpl1
defined class ZZ

scala> class ZZ extends XImpl2
<console>:40: error: illegal inheritance;
 self-type ZZ does not conform to b.XImpl2's selftype b.XImpl2 with b.X
       class ZZ extends XImpl2
                        ^
scala> class ZZ extends XImpl1 with XImpl2 // XImpl2 still can be mixed but only if XImpl1 present in linearization
defined class ZZ

甚至有几个:

trait A {
   type X1 <: XLike
   type X2 <: XLike

   trait XLike { this: X1 with X2 => }
} 

trait B extends A {
    type X1 = XImpl1  
    type X2 = XImpl2

    trait XImpl1 extends XLike { this: X1 with X2 => }
    trait XImpl2 extends XLike { this: X1 with X2 => }
    trait XImpl3 extends XLike { this: X1 with X2 => }
}

在实践中,X1X2可能会扮演一些重要角色。例如,如果你做了一个resposibilty链(stackable traits) - 你可以按任何顺序混合许多特征(而不是所有特征 - 可能都有特征组),所以它很好能够指定一个或几个强制处理程序(只是为了不忘记它们),如:

 val a = new Logic with Hanler with Group0
 trait Group0 extends MandatoryHandler1 with Group1 with H2
 trait Group1 extends H3 with H4 with MandatoryHandler2
 trait Group2 extends H2 with H5

如果您将Group0更改为Group2,您可能会失去MandatoryHandler2(例如,可能是某位记者)。

另一个:图书馆开发人员可能会提供许多特征,以简明扼要的Single Resposibilty / Interface Segregation原则,但其中一些应该总是由玩这个乐高的用户混合在一起。

所以这里是经典的OOP-composition聚合方式(需要实例):

 abstract class B {
    val helper1: H1 //mandatory, exactly H1, not some H
    val helper2: H2 
 }

 class C extends B {
    val helper1 = new H1 //mandatory, exactly H1, not some H
    val helper2 = new H2 
 }
 class H1 extends H {...} 
 class H2 extends H {...}    

vs mix-in方式:

 trait B extends A {
   type helper1 = H1
   type helper2 = H2

   trait H1 extends H // no abstract members here just mix-in
   trait H2 extends H
 }

 trait C extends H1 with H2