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

参考

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:_*)

你可能感兴趣的:(scala,Scala,初体验)