scala类型系统:4) 内部类,路径依赖类型&类型投影
2016-11-09 09:47
225 查看
scala类型系统:4) 内部类,路径依赖类型&类型投影
先回顾一下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实例,注意创建内部类的时候
Outter.Inner i1 = o1.new Inner();
在用new创建内部类时,前边必须限定外部对象(内部类实例必须要访问到外部对象引用):o1;如果是在 Outter类内部这个外部引用可以省略,它默认会用传递外部this引用。
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) <console>:12: error: type mismatch; found : a2.B required: a1.B
按照方法的提示: 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也是不同的类型。路径依赖类型的路径完整写法:
1) 内部类定义在object里面,路径:package.object.Inner
object Singleton { class Inner } val x = new p1.p2.p3.Singleton.Inner
2) 内部类定义在class/trait 里
//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 }
那现在的问题来了,怎么让 a1.foo 方法可以接收 b2 参数 ?
class A { class B; def foo(b:B) // 接收所有的B类型实例,而不只是foo的调用者实例(a1)路径下B类型的对象 println(b) }
这又引出一个概念:类型投影(type projection)
在scala里,内部类型(排除定义在object内部的),想要表达所有的外部类A实例路径下的B类型,即对
a1.B和
a2.B及所有的
an.B类型找一个共同的父类型,这就是类型投影,用
A#B的形式表示。
A#B / \ / \ a1.B a2.B
这样,我们只要修改一下 foo 方法里的参数类型
def foo(b: A#B)
就可以调用
a1.foo(b2)了。
我们回头来对比一下scala里的类型投影与java里的内部类型的概念,java里的内部类型在写法上是 Outter.Inner 它其实等同于scala里的投影类型 Outter#Inner,java里没有路径依赖类型的概念,比较简化。
转载自:http://hongjiang.info/scala/ 推荐大家阅读下这位大哥出版的书《Scala函数式编程》
相关文章推荐
- scala类型系统:9) this别名&自身类型
- scala类型系统:11) upper bounds & lower bounds
- scala类型系统:11) upper bounds & lower bounds
- 机房收费系统之数据类型&除法运算符
- Scala类型 9:自身类型 & this别名
- 52_PHP的文件系统操作(一)文件的类型与属性(53)PHP文件处理(二)文件路径及操作和权限
- &菜鸟收藏:熟知Word箭头样式类型设置&【系统收藏】
- 将ext3转换为ext2 && 查询分区文件系统类型 [转]
- scala学习之:链式风格及路径依赖
- Scala in depth 6 Scala的类型系统 下
- Scala类型 6:复合类型 & with关键字
- 解决Visual Studio编译出现Moc'ing文件,系统找不到指定路径问题
- "路径和文件名总长度必须不能超过 260 个字符! 系统找不到指定的路径"的解决方法
- 解决VS编译出现Moc'ing文件,系统找不到指定路径问题
- Scala 深入浅出实战经典 第52讲:Scala中路径依赖代码实战详解
- Scala类型 11: Upper Bounds & Lower Bounds
- 验证配置设置时发生错误,已引发类型为System.Runtime.InteropServices.COMException的异常。其他异常信息:系统找不到指定的路径
- C# Office编程——Word 错误类型:“系统找不到 Microsoft.Office.Interop.Word"
- 更改数据字段类型提示消息!对象'DF__Dress_Rev__Choos__333C5566' 依赖于 列'ChooseComplete'
- Linux 虚拟文件系统支持的文件系统类型-3----sysfs && procfs