Scala Path-dependent types 路径依赖 inner class 内部类

Scala Path-dependent types 路径依赖,它使用”井号” 运算符 #, 具体的代码形式是 代码R#X[R#Next]。类似于 Java 的Outer.Inner.一般常用在定义参数类型

In Scala it is possible to let classes have other classes as members. As opposed to Java-like languages where such inner classes are members of the enclosing class, in Scala such inner classes are bound to the outer object. Suppose we want the compiler to prevent us, at compile time, from mixing up which nodes belong to what graph. Path-dependent types provide a solution.

Scala Path-dependent types是其一种特殊的语法表现形式,它使用”井号” 运算符 ==#== , 具体的代码形式是 代码R#X[R#Next]。类似于 Java 的Outer.Inner(Outer和Inner都是类,一个外部类,一个内部类);
一般常用在定义参数类型,使用的是内部类,则用这个方式来定义类型。

Java 的语言中,内部类是外部类的成员,而 Scala 正好相反,内部类是绑定到外部对象的。

talk is cheap, show me the code

 /**
   * 路径依赖 Path-dependent types
   *
   */
 // 定义外部类,内部类
 class Outer(val width: Int, val height : Int){

   class Inner{
     private val space = width * height

     def show(): Unit ={
       println(" the space is equal : " + space)
     }
   }
 }

 object PathDependence {
   def main(args: Array[String]) {
     val outer = new Outer(6, 8)
     val inner = new outer.Inner
     inner.show()
     // 特定类型的内部类
     val inner_belong_outer : outer.Inner = new outer.Inner
     inner_belong_outer.show()

     val another_other = new Outer(3, 4)
     val use_inner : Outer#Inner = new another_other.Inner // # 表示Inner是Outer的内部类
     use_inner.show()

   }
 }

 // println --> 48, 48 , 12

所谓路径,指的就是参考外部类所建立的实例的名称。 就outer.Inner这个类型来说,路径为outer。更重要的是,不同路径代表不同的类型。

路径依赖的是路径的名称,与路径所引用的实例无关

val o1 = new Outer
val o2 = o1
val i1: o1.Inner = new o1.Inner
val i2: o2.Inner = new o1.Inner   // 编译错误。
// 尽管o2和o1引用同一个实例,但o1.Inner和o2.Inner是不同的,Scala编译器只根据路径名进行区分

事实上, o1.Inner和o2.Inner都是Outer#Inner的子类型


    val o1 = new Outer
    val o2 = new Outer
    val i1: Outer#Inner = new o1.Inner
    val i2: Outer#Inner = new o2.Inner

路径依赖类型可以被继承

    val o = new Outer
    class Some extends o.Inner
    val oi: Outer#Inner = new Some

Outer#Inner是不能被继承的; 此外,路径依赖类型所在的路径必须是不可变的值。

    var o1 = new Outer
    val i = new o1.Inner   // 编译错误。因为o1是var

这也很好理解,如果o1是var,那么他的类型将是不确定的,从而导致其路径依赖类型也不确定。

一般地,x0.x1.x2…xn。T是路径一类类型,只要满足:

a) x0 是不可变值(即x0是val所声明的变量)

b) x1, x2, ..., xn 都是不可变的属性

c) T 是xn内部类 
    class Food

    class Fish extends Food {
        override def toString = "魚"
    }

    abstract class Animal {
        type F <: Food
        def eat(f: F)
    }

    class Cat extends Animal {
        type F = Fish
        def eat(fish: Fish) {
            println("吃" + fish)
        }
    }

    val cat1 = new Cat
    val cat2 = new Cat
    cat1.eat(new cat1.F)  // 吃魚
    cat2.eat(new cat2.F)  // 吃魚

对于Cat类而言,F是其类型成员之一, 但这里 cat1.F和cat2.F代表相同的类型,也就是说你可以把一个cat2.F类型的实例传递给一个声明为cat1.F类型的变量. 实际上,上述代码的最后四行等价于以下的代码: 当然new Cat#F也是合法的

    type F1 = Fish
    type F2 = Fish
    cat1.eat(new F1)   // 吃魚
    cat1.eat(new F2)   // 吃魚

发表回复