美文网首页
scala 内部类、路径依赖类型、类型投影

scala 内部类、路径依赖类型、类型投影

作者: scandly | 来源:发表于2018-08-16 21:26 被阅读0次

    先回顾一下java的内部类

    class Outter{

        public class Inner {}

        public void foo(Inner c){

            System.out.println(c);

        }

    }

    public class Main {

        public static void main(String[] args)throws Exception{

            Outter o1 = new Outter();

            Outter o2 = new Outter();

            Outter.Inner i1 = o1.new Inner();

            Outter.Inner i2 = o2.new Inner();

            o1.foo(i2);

        }

    }

    Outter类定义了内部Inner类,在main里创建了两个Inner实例

    注意new内部类的时候用 Outter.Inner i1 = o1.new Inner();

    前边必须限定外部对象;

    class Outter {

        public class Inner{}

        public void test() {

            new Inner(); // 相当于this.new Inner(); 也可以写为Outter.this.new Inner();

        }

    }

    同样的事情翻译为scala代码:

    scala> class A {

                class B;

                def foo(b:B) = println(b)

            }

    scala> val a1 = new A

    scala> val a2 = new A

    scala> val b1 = new a1.B

    scala> val b2 = new a2.B

    在创建内部类的时候,语法上与java有所不同,不是 outter.new Inner() 而是 new outter.Inner(),看上去只是表象不同么?实际上,scala有很大差异,不同于java里 i1 和 i2 类型是相同的,否则 o1.foo(i2) 就不能执行了,scala里的 b1 和 b2 是不同的类型:

    scala> a1.foo(b2)

    :12: error: type mismatch;

    a1.foo方法接受的参数类型为:a1.B,而传入的b2 类型是 a2.B,两者不匹配。

    验证一下:

    scala> typeOf[a1.B] == typeOf[a2.B]

    res2: Boolean = false

    确实是不一样的类型,它跟外部的实例相关,那个foo方法参数类型B的写法是缩写,省略了路径:

    def foo(b: B) // 相当于 this.B 或 A.this.B

    这里要引入一个概念:路径依赖类型(见最下面);比如上面的 A.this.B 就是一个路径依赖类型,B 前面的路径 A.this 随着不同的实例而不同,比如 a1 和 a2 就是两个不同的路径,所以a1.B 与 a2.B也是不同的类型。

    那现在的问题来了,怎么让 a1.foo 方法可以接收 b2 参数 ?

    class A {

        class B;

        def foo(b:B)  // 接收所有的B类型实例,而不只是foo的调用者实例(a1)路径下B类型的对象        println(b)

    }

    这又引出一个概念:类型投影(type projection)

    在scala里,内部类型(排除定义在object内部的),想要表达所有的外部类A实例路径下的B的type(类型),即对 a1.B 和 a2.B 类型找一个共同的父类型,这就是类型投影,用 A#B的形式表示。

            A#B

            / \

          /  \

        a1.B  a2.B

    这样,我们只要修改一下 foo 方法里的参数类型

    def foo(b: A#B)

    就可以调用 a1.foo(b2) 了。

    路径依赖类型的路径完整写法

    路径不是类型,而是类似某种位置。

    1) 内部类定义在object里面,路径:package.object.Inner

    object Singleton {

        class Inner

    }

    val x = new p1.p2.p3.Singleton.Inner

    2) 内部类定义在class

    //2.1) 直接在外部类中使用内部类型,路径:this 或 Outter.this

    class A {

        class B

        val b = new B // 相当于 A.this.B

    //2.2) 在子类中使用父类的内部类型,路径:super 或 Child.super

    class A  { class B }

    class C extends A { val x = new super.B } // 相当于 C.super.B

    //2.3) 在其他类中使用,路径:outter(外部类实例)

    class A  { class B }

    class C {

        val a = new A

        val x = new a.B 

    }

    相关文章

      网友评论

          本文标题:scala 内部类、路径依赖类型、类型投影

          本文链接:https://www.haomeiwen.com/subject/zgqabftx.html