Scala编程(第13章:包和引入)

1.将代码放进包里:在Scala中,可以通过两种方式将代码放进带名字的包里。第一种是在文件顶部放置一个package子句,让整个文件的内容放进指定的包:

package bobsrockets.navigation
class Navigator

另一种将Scala代码放进包的方式更像是C#的命名空间。可以在package子句之后加上一段用花括号包起来的代码块,这个代码块包含了进入该包的定义。这个语法称为打包:

package bobsrockets.navigation{
  class Navigator
}

效果跟上面一样。这样更通用的表示法可以让我们在一个文件里包含多个包的内容。如,可以把某个类的测试代码跟原始代码放在同一个文件里,不过分成不同的包:

package bobsrockets{
  package navigation{
    //位于bobsrocket.navigation包中
    class Navigator
    package tests{
      //位于bobsrocket.navigation.tests包中
      class NavigatorSuite
    }
  }
}

 

2.对相关代码的精简访问:可以访问同一个包里的其它成员:

package navigation{
  class Navigator{
    //不需要navigation.StarMap
    val map=new StarMap
  }
  class Ship
}

每个你能编写的顶层包都被当作是_root_包的成员。

 

3.引入:在Scala中,我们可以用import子句引入包和它们的成员:

//到Fruit的便捷访问
import bobsdelights.Fruit
//到bobsdelights所有成员的便捷访问
import bobsdelights._
//到Fruit所有成员的便捷访问
import bobsdelights.Fruit._

Scala的引入可以出现在任何地方,不仅仅是在某个编译单元的最开始,它们还可以引用任意的值:

abstract class Fruit(val name:String,val color:String)

def showFruit(fruit:Fruit){
  import fruit._
  println(name+"s are"+color)
}

在Scala中,引入可以

  • 出现在任意位置
  • 引用对象(不论是单例还是常规对象),而不只是包
  • 让你重命名并隐藏某些被引入的成员
object Fruits{
  object Apple extends Fruit("apple","red")
  object Orange extends Fruit("orange","orange")
  object Pear extends Fruit("pear","yellowish")
}

import Fruits.{Apple,Orange}

这只会从Fruits对象引入Apple和Orange两个成员。

import Fruits.{Apple=>McIntosh,Orange}

引入Orange和Apple,并将Apple改名为McIntosh。重命名后可以用Fruits.Apple或McIntosh来访问成员。重命名子句形式是“<原名> => <原名>”。

import Fruits.{_}

这将引入Fruits所有成员,跟import Fruiits._的含义是一样的。

import Fruits.{Apple=>McIntosh,_}

引入Fruits所有成员,但会把Apple重命名为McIntosh。

import Fruits.{Pear=>_,_}

引入除Pear之外的所有成员。形如“<原名> => _”的子句将在引入的名称中排除<原名>。从某种意义上讲,将某个名称重命名为“_”意味着将它完全隐藏掉。总之,引入选择器可以包含:

  • 一个简单的名称x。这将把x包含在引入的名称集里。
  • 一个重命名子句x=>y。这会让名为x的成员以y的名称可见。
  • 一个隐藏子句x=>_。这会从引入的名称集里排除掉x。
  • 一个捕获所有的“_”。这会引入除了之前子句中提到的成员外的所有成员。如果要给出捕获所有子句,它必须出现在引入选择列表的末尾。

 

4.隐式引入:Scala对每个程序都隐式地添加了一些引入。本质上,这就好比每个扩展名为“.scala”的源码文件的顶部都添加了如下三行引入子句:

import java.lang._  //java.lang包的全部内容
import scala._      //scala包的全部内容
import Predef._     //Predef对象的全部内容

      由于scala是隐式引入的,举例来说,可以直接写List,而不是scala.List。

      Predef对象包含了许多类型、方法和隐式转换的定义,这些定义在Scala程序中经常被用到。

      Scala对这三个引入子句做了一些特殊处理,后引入的会遮挡前面的。举例来说,scala包和Java1.5版本后的java.lang包都定义了StringBuilder类。由于scala的引入遮挡了java.lang的引入,因此StringBuilder这个简单名称会引用到scala.StringBuilder,而不是java.lang.StringBuilder。

 

5.访问修饰符:Scala对访问修饰符的处理大体上跟Java保持一致,不过有些区别。

私有成员:Scala对私有成员的处理跟Java类似。标为private的成员只在包含该定义的类或对象内部可见。在Scala中,这个规则同样适用于内部类。但Java可以从外部类访问其内部类的私有成员。

受保护成员:跟Java相比,Scala对protected成员的访问也更严格。在Scala中,protected的成员只能从定义该成员的子类访问。而Java允许同一个包内的其他类访问这个类的受保护成员。Scala提供了另一种方式来达到这个效果,因此protected不需要为此放宽限制。

公共成员:Scala并没有专门的修饰符用来标记公共成员:任何没有被标为private或protected的成员都是公共的。公共成员可以从任何位置访问到。

保护的范围:我们可以用限定词对Scala中的访问修饰符机制进行增强。形如private[X]或protected[X]的修饰符的含义是对此成员的访问限制“上至”X都是私有或受保护的,其中X表示某个包含该定义的包、类或单例对象。我们可以用protected[X],那么X表示的包、类或对象中,都能访问这个被标记的定义。如果X是包名,那就跟Java的protected一样了。

      Scala还提供了比private限制范围更小的访问修饰符。被标记为private[this]的定义,只能在包含该定义的同一个对象中访问。这样的定义被称作是对象私有的。

可见性和伴生对象:一个类会将它的所有访问权跟它的伴生对象共享,反过来也一样。

 

6.包对象:如果你有某个希望在整个包都能用的助手方法,大可将它放在包 顶层具体的做法是把定义放在包对象当中。每个包都允许有一个包对象,任何被放在包对象里的定义都会被当作这个包本身的成员:

//位于文件bobsdelights/package.scala中
package object bobsdelights {
  def showFruit(fruit:Fruit)={
    import fruit._
    println(name+"s are"+color)
  }
}

和打包的区别是包对象包含了一个object关键字。这是一个包对象,而不是一个包。包对象经常用于包级别的类型别名和隐式转换。顶层的scala包也有一个包对象,其中的定义对所有Scala代码都可用。

      包对象会被编译成名为package.class的类文件,该文件位于它增强的包的对应目录下。源文件最好能保持相同的习惯,也就是说我们一般会将包对象bobsdelights的源码放在bobsdelights目录下名为package.scala的文件当中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值