淺談Scala 2.8的包對象(package object)

        Scala 2.8提供包對象(package object)的新特性。什麼是包對象呢?按個人理解,根據Scala「一切皆對象」設計哲學,包(package)也是一種對象。既然是對象,那麼就應該有屬性和方法,也能夠在包對象內聲明某個類型的別名。舉個例 java

package  com{
  package object ggd543{
    type HashMap[A,B] = scala.collection.mutable.HashMap[A,B];
    val HashMap =  scala.collection.mutable.HashMap
    def print = println("hello, ggd543")
  }

  package object aiguozhe{
    var name = "aiguozhe"
    def sayHello = println("hello")
  }
  
}

 能夠看到,定義包對象跟定義一個普通的伴隨對象(companion object)在寫法上的惟一區別就是在關鍵字object 前加上 package 。程序員

而後咱們能夠像使用伴隨對象那樣使用包對象,好比app

object Test extends Application{
    val myMap: com.ggd543.HashMap[String,String]= null;   
    println(com.ggd543.HashMap)   
    println(com.ggd543.print);    
    println(com.aiguozhe.name)
    com.aiguozhe.name = "AIGUOZHE"
    println(com.aiguozhe.name)
}

若是包對象的做用僅僅限於伴隨對象那樣,那scala 2.8徹底沒有必要引入這種特性。實際上包對象最重要的用途是兼容舊的類庫,或者爲某些數據類型提供加強版本。ide

好比在scala 2.7.7中,List是定義在scala包下的一個不可變集合類。這樣作的目的是每次使用List的時候不須要顯式地導入包名,由於List是一個使用很頻繁的類。ui

在Scala中,包java.lang,包scala和伴隨對象Predef裏的全部數據類型,屬性和方法會被自動導入到每一個Scala文件中

然而另外一方面,List因爲具備不可變的特性,它應該納入scala.collection.immutable包中。所以在scala 2.8中,List被挪到scala.collection.immutable包下里,但這樣一來2.8版本如何兼容2.7.7版本。因而Scala 2.8引入「包對象」這個特性來解決這個問題。若是你查閱Scala 2.8版本的API文檔或源碼,你會發現它定義了一個包對象:scala

package object scala { 
 
  // Type and value aliases for collection classes
 
  type TraversableOnce[+A] = scala.collection.TraversableOnce[A] 
 
  type Traversable[+A] = scala.collection.Traversable[A]
  val Traversable = scala.collection.Traversable
 
  type Iterable[+A] = scala.collection.Iterable[A]
  val Iterable = scala.collection.Iterable
 
  type Seq[+A] = scala.collection.Seq[A]
  val Seq = scala.collection.Seq
 
  type IndexedSeq[+A] = scala.collection.IndexedSeq[A]
  val IndexedSeq = scala.collection.IndexedSeq
 
  type Iterator[+A] = scala.collection.Iterator[A]
  val Iterator = scala.collection.Iterator
 
  type BufferedIterator[+A] = scala.collection.BufferedIterator[A]
 
  type List[+A] = scala.collection.immutable.List[A]
  val List = scala.collection.immutable.List
 
  val Nil = scala.collection.immutable.Nil
  
  type ::[A] = scala.collection.immutable.::[A]
  val :: = scala.collection.immutable.::
 
  type Stream[+A] = scala.collection.immutable.Stream[A]
  val Stream = scala.collection.immutable.Stream
  val #:: = scala.collection.immutable.Stream.#::
 
  type Vector[+A] = scala.collection.immutable.Vector[A]
  val Vector = scala.collection.immutable.Vector
   
  type StringBuilder = scala.collection.mutable.StringBuilder
 
  type Range = scala.collection.immutable.Range
  val Range = scala.collection.immutable.Range
 
  // Numeric types which were moved into scala.math.*
   
  type BigDecimal = scala.math.BigDecimal
  val BigDecimal = scala.math.BigDecimal
   
  type BigInt = scala.math.BigInt
  val BigInt = scala.math.BigInt
   
  type Equiv[T] = scala.math.Equiv[T]
  type Fractional[T] = scala.math.Fractional[T]
  type Integral[T] = scala.math.Integral[T]
 
  type Numeric[T] = scala.math.Numeric[T]
  val Numeric = scala.math.Numeric
   
  type Ordered[T] = scala.math.Ordered[T]
  val Ordered = scala.math.Ordered
   
  type Ordering[T] = scala.math.Ordering[T]
  val Ordering = scala.math.Ordering
   
  type PartialOrdering[T] = scala.math.PartialOrdering[T]    
  type PartiallyOrdered[T] = scala.math.PartiallyOrdered[T]

   //  others 

}

也就是說scala.List至關於指向了scala.collection.immutable.List,從而保證升級到Scala 2.8版本不會對原有的程序形成影響。

可能有些讀者會問,經過定義一個伴隨對象scala 可否解決兼容的問題?但細想一下就發現不妥,由於scala包下的一切都要搬到這個伴隨對象scala中去了,這彷佛不太現實。實際上,Scala編譯器會在scala包下建立一個叫package的類,這個類裏面的內容就是package object scala中的東西, scala.List被翻譯成scala.package.List, 但對於程序員來講是透明的 。一樣道理也會在com.ggd543包和com.aiguozhe包下分別建立一個package類.翻譯

有了包對象這個新特性,咱們不但解決了新舊版本的兼容性問題,還能夠對舊的類庫或第三方接口作一些包裝或改進,而不須要額外建立一些類或接口(雖然實際上仍是建立了一個類package,但這是編譯器幫咱們完成的)。好比在Play-scala module的0.8版本(http://www.playframework.org/modules/scala-0.8.zip)中,就對一些JPA接口進行了封裝和改進:設計

import play.data.validation._
import javax.persistence

package play { 
    
  package db {
  import annotation.target.field

  package object jpa{
      //enums
      val CascadeType = CascadeTypeWrapper
      val LockModeType = LockModeTypeWrapper
      val FetchType = FetchTypeWrapper
      //classes
      type Table = persistence.Table
      type Entity = persistence.Entity
      type Inheritance = persistence.Inheritance

      //javax.persistence field
      type  AttributeOverrides = persistence.AttributeOverrides @field
      type  Basic = persistence.Basic  @field
      type  Column = persistence.Column @field
  // ...
}
相關文章
相關標籤/搜索