您的位置:首页 > 其它

[3.0]数组的创建及原理初探

2016-05-24 10:45 351 查看

参考

ClassTag API

泛型的理解与应用

上下文界定

类型系统

问题

怎么理解scala中数组的创建方式? T:ClassTag如何类理解?

def makeArray[T:ClassTag](elems  : T*):Array[T] = Array[T](elems:_*) // 创建任意类型的数组


分析

第一、makeArray方法体中的 语句:
Array[T](elems:_*)
会调用Array的伴生对象中apply方法,具体实现如下:

def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for (x <- xs.iterator) { array(i) = x; i += 1 }
array
}


第二、数组创建的方法申明:
def makeArray[T:ClassTag](elems  : T*):Array[T]
等价于
def makeArray[T] (elems  : T*)(implicit elem:ClassTag[T]):Array[T]
详见上下文绑定

综合一、二两条,详细版的数组创建方式如下:

def makeArray[T] (elems  : T*)(implicit  elem:ClassTag[T]):Array[T] ={
val arr = new Array(elems.length)
var i = 0
for(item<-elems){
arr(i) = item;  i+=1
}
arr
}


那么问题来了,这里为什么需要添加一个隐式参数ClassTag[T]呢?我们用反证法来加以说明-假设没有ClassTag[T]. 没有ClassTag[T]的话,由于上述方式创建的数组,其存储空间是在运行时分配的,而类型信息T在运行时已被擦除(参见泛型原理)也就是说程序运行时不知道T到底是什么类型-Int、Long还是其他类型?这样就无法创建数组:不知道应该为数组中的每个元素分配多大的内存空间!

ClassTag[T]的出现正是为了解决这个问题的 - “A ClassTag[T] stores the erased class of a given type
T
, accessible via the runtimeClass field ” - ClassTag会把T的具体类型信息保留到程序运行期,至于内部是如何实现的,有待后续进一步分析。

总结

以后就放心大胆地使用简洁版的方式创建数组吧:

def makeArray[T:ClassTag](elems  : T*):Array[T] = Array[T](elems:_*)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: