scala类型系统:20) 数组类型

scala类型系统:20) 数组类型

在java里,引用类型的数组类型是支持协变的,即 String[] 类型是 Object[] 的子类型,martin问过gosling,回答是希望有一个通用处理数组的简单方法。

void sort(Object[] a, Comparator cmp) { … }

数组的协变被用来确保任意参数类型的数组都可以传入排序方法。随着java引入了泛型,sort方法可以用类型参数,因此数组的协变不再有用。只是考虑到兼容性。

scala里不支持数组的协变,以尝试保持比java更高的纯粹性。即 Array[String]的实例对象不能赋给Array[Any]类型的变量。

在数组的设计上,scala是走过弯路的,这里有篇文章翻自martin写的关于scala2.8数组的paper,已经解释的非常好了。

正是因为2.8中的数组背后的实现要与java保持一致,使得通过泛型创建某个数组时

def test[T]() {
    val a = new Array[T] //运行时类型缺失,无法创建对应的java数组
}

因为java里的数组,实际会对应int[],float[],char[],等8个基础类型数组,与1个支持协变的引用类型数组。

更细的看一下java引用类型的数组类型:

scala> class A { 
|       val a1 = new Array[java.lang.Object](1);
|       val a2 = new Array[String](1);
| }

scala> :javap A    
...
//  a1:[Ljava/lang/Object;
...
//  a2:[Ljava/lang/String;

看到String[]会被编译器翻译为[Ljava/lang/String,而Object[]被翻译为[Ljava/lang/Object,其实可以看做是一种泛型类型的特例,[L 是类型构造器,StringObject 等是类型参数。但不同于java里其他泛型集合的实现,数组类型中的类型参数在运行时是必须的,即 [Ljava/lang/String 与[Ljava/lang/Object 是两个不同的类型,不像 Collection<String> 与 Collection<StringBuilder>运行时参数类型都被擦拭掉,成为Collection<Object>

为此,2.8中不得不引入了Manifest来保存T在运行时的类型信息(参考上一篇对Manifest与TypeTag的介绍),从而保证运行时scala数组与java的数组实现一致。

转载自:http://hongjiang.info/scala/ 推荐大家阅读下这位大哥出版的书《Scala函数式编程》

展开阅读全文

没有更多推荐了,返回首页