浅谈Scala 2.8的包对象(package object)

Scala 2.8提供包对象(package object)的新特性。什么是包对象呢?按我的理解,根据Scala“一切皆对象”设计哲学,包(package)也是一种对象。既然是对象,那么就应该有属性和方法,也可以在包对象内声明某个类型的别名。举个例 

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 。

然后我们可以像使用伴随对象那样使用包对象,比如

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完全没有必要引入这种特性。实际上包对象最重要的用途是兼容旧的类库,或者为某些数据类型提供增强版本。

比如在scala 2.7.7中,List是定义在scala包下的一个不可变集合类。这样做的目的是每次使用List的时候不需要显式地导入包名,因为List是一个使用很频繁的类。

在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文档或源码,你会发现它定义了一个包对象:

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
  // ...
}


原文链接:https://my.oschina.net/aiguozhe/blog/35202?p=1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值