Scala详解---------包和引用


包和引入

摘要:

在本篇中,你将会了解到Scala中的包和引入语句是如何工作的。相比Java不论是包还是引入都更加符合常规,也更灵活一些。本篇的要点包括:

1. 包也可以像内部类那样嵌套

2. 包路径不是绝对路径

3. 包声明链x.y.z并不自动将中间包x和x.y变成可见

4. 位于文件顶部不带花括号的包声明在整个文件范围内有效

5. 包对象可以持有函数和变量

6. 引入语句可以引入包、类和对象

7. 引入语句可以出现在任何位置

8. 引入语句可以重命名和隐藏特定成员

9. java.lang、scala和Predef总是被引入


Scala中包含义

Scala的包和Java中的包或者C++中的命名空间的目的是相同的:管理大型程序中的名称。举例来说,Map这个名称可以同时出现在scala.collection.immutable和scala.
collection.mutable包而不会冲突。要访问它们中的任何一个,你可以使用完全限定的名称scala.collection.immutable.Map或scala.collection.mutable.Map,也可以使用引入语句来提供一个更短小的别名

要增加条目到包中,你可以将其包含在包语句当中,比如:

package com {

package horstmann {

package impatient {

class Employee

…….

}

}

}

这样一来类名Employee就可以在任意位置以com.horstmann.impatient.Employee访问到了

Scala中包定义

与对象或类的定义不同,同一个包可以定义在多个文件当中。前面这段代码可能出现在文件Employee.scala中,而另一个名为Manager.scala的文件可能会包含:

package com {

package horstmann {

package impatient {

class Manager

…….

}

}

}

这说明了,源文件的目录和包之间并没有强制的关联关系。你不需要将Employee.scala和Manager.scala放在com/horstmann/impatient目录当中

换个角度讲,你也可以在同一个文件当中为多个包贡献内容。Employee.scala文件可以包含:

package com {

package horstmann {

package impatient {

class Employee

…….

}

}

}

package org {

package bigjava {

class Counter

…….

}

}


作用域规则

包嵌套

在Scala中,包的作用域比起java来更加前后一致。Scala的包和其他作用域一样地支持嵌套,你可以访问上层作用域中的名称。例如:

package com {

package horstmann {

object Utils {

def percent of (value: Double, rate: Double) = value*rate/100

……….

}

package impatient {

class Employee

…….

def giveRaise( rate : Scala.Double) {

salary += Utils.percentOf( salary,rate )

}

}

}

}

注意Utils.percentOf修饰符。Utils类定义于父包,所有父包中的内容都在作用域内,因此没必要使用com.horstmann.Utils.precentOf。

包冲突

不过,这里有一个瑕疵。假定有如下代码:

package com {

package horstmann {

package impatient {

class Manager {

val suboardinates = new collection.mutable.ArrayBuffer[Employee]

…….

}

}

}

}

这里我们利用到一个特性,那就是scala包总是被引入。因此,collection包实际上指向的是scala.collection。现在假定有人加入了如下的包,可能位于另一个文件当中:

package com {

package horstmann {

package collection {

…….

}

}

}

这下Manager类将不再能通过编译。编译器尝试在com.horstmann.collection包中查找mutable成员未果。Manager类的本意是要使用顶级的scala包中的collection包,而不是随便什么存在于可访问作用域中的子包

包冲突方案

在Java中,这个问题不会发生,因为包名总是绝对的,从包层级的最顶端开始。但是在Scala中,包名是相对的,就像内部类的名称一样。内部类通常不会遇到这个问题,因为所有代码都在同一个文件当中,由负责该文件的人直接控制。但是包不一样,任何人都可以在任何时候向任何包添加内容。

解决方法之一是使用绝对包名,以_root_开始,例如:

val subordinates=new
_root_.scala.collction.mutable.ArrayButfer[Employee]

另一种做法是使用"串联式"包语句,在后面会详细讲到


串联式包语句

包语句可以包含一个"串",或者说路径区段,例如:

package com.horstmann.impatient { // com和com.horstmann的成员在这里不可见

package people {

class Person

}

}

这样的包语句限定了可见的成员。现在com.horstmann.collection包不再能够以collection访问到了


文件顶部标记法

除了我们到目前为止看到的嵌套标记法外,你也可以在文件顶部使用package语句,不带花括号。例如:

package com.horstmann.impatient

package people

class Person

这等同于

package com.horstmann.impatient {

package people {

class Person

……

// 直到文件末尾

}

}

如果文件中的所有代码属于同一个包的话:这也是通常的情形,这是更好的做法。还需注意是:在上面的示例当中,文件的所有内容都属于com.horstmann.impatient.people,但com.horstmann.impatient包的内容是可见的,可以被直接引用


包对象

包可以包含类、对象和特质,但不能包含函数或变量的定义。很不幸,这是Java虚拟机的局限。把工具函数或常量添加到包而不是某个Utils对象,这是更加合理的做法。包对象的出现正是为了解决这个局限。每个包都可以有一个包对象。你需要在父包中定义它,且名称与子包一样。例如

package com.horstmann.impatient

package object
people {

val defaultName="John Q. Public"

}

package people {

class Person {

var name=defaultName // 从包对象拿到的常置

}

…….

}

}

注意defaultName不需要加限定词,因为它位于同一个包内。在其他地方,这个常量可以用com.horstmann.impatient.people.defaultName访问到。在幕后,包对象被编译成带有静态方法和字段的JVM类,名为package.class,位于相应的包下。对应到本例中,就是com.horstmann.impatient.people.package,其中有一个静态字段defaultName。在JVM中,你可以使用package作为类名。对源文件使用相同的命名规则是好习惯,可以把包对象放到文件com/horstmann/impatient/people/package.scala。这样一来,任何人想要对包增加函数或变量的话,都可以以很容易地找到对应的包对象


包可见性

在Java中,没有被声明为public、private或protected的类成员在包含该类的包中可见。在Scala中,你可以通过修饰符达到同样的效果。以下方法在它自己的包中可见:

package com.horstmann.impatient.people

class Person {

private[people] def description="A person with name "+name

…….

}

你可以将可见度延展到上层包:

private[impatient] def description="A person with name "+name


引入

引入语句让你可以使用更短的名称而不是原来较长的名称。写法如下:

import java.awt.Color

这样一来,你就可以在代码中写Color而不是java.awt.Color了,这就是引入语句的唯一目的。如果你不介意长名称,你完全不需要使用引入。你也可以引入某个包的全部成员:

import java.awt._

这和Java中的通配符*一样。在Scala中,*是合法的标识符。你完全可以定义com.horstmann.*.people这样的包,但请别这样做。你还可以引入类或对象的所有成员:

import java.awt.Color._

val c1 =RED // Color.RED

val c2=decode("#ff0000") // Color.decode

这就象Java中的import static。Java程序员似乎挺害怕这种写法,但在Scala中这样的弓很常见。一旦你引入了某个包,你就可以用较短的名称访问其子包。例如:

import java.awt._

def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent

……….

}

event包是java.awt包的成员,因此引入语句把它也带进了作用域


任何地方都可以声明引入

在Scala中,import语句可以出现在任何地方,并不仅限于文件顶部。import语句的效果一直延伸到包含该语句的块末尾。例如:

class Manager {

import scala.collection.mutable._

val subordinates = new ArrayBuffer[Employee]

}

这是个很有用的特性,尤其是对于通配引入而言。从多个源引入大量名称总是让人担心。事实上,有些Java程序员特别不喜欢通配引入,以至于从不使用这个特性,而是让IDE帮他们生成一长串引入语句。通过将引入放置在需要这些引入的地方,你可以大幅减少可能的名称冲突。


重命名和隐藏方法

重命名

如果你想要引人包中的几个成员,可以像这样使用选取器( selector):

import java.awt.Color.{ Color,Font }

选取器语法还允许你重命名选到的成员:

import java.util.{ HashMap=>JavaHashMap }

import scala.collection.mutable._

这样一来,JavaHashMap就是java.utiI.HashMap,而HashMap则对应scala.collection.mutable.HashMap。

隐藏方法

选取器HashMap =>_将隐藏某个成员而不是重命名它。这仅在你需要引入其他成员时有用:

import java.util.{HashMap=>_,_ }

import scala.collection.mutable._

现在,HashMap无二义地指向scala.collection.mutable.HashMap,因为java.util.HashMap被隐藏起来了


隐式引入

每个Scala程序都隐式地以如下代码开始:

import java.lang._

import scala._

import Predef._

和Java程序一样,java.lang总是被引入。接下来,scala包也被引入,不过方式有些特殊。不像所有其他引入,这个引入被允许可以覆盖之前的引入。举例来说,scala.StringBuilder覆盖java.lang.StringBuilder而不是与之冲突。最后,Predef对象被引入。它包含了相当多有用的函数,这些同样可以被放置在scala包对象中,不过Predef在Scala还没有加入包对象之前就存在了。

由于scala包默认被引入,对于那些以scala开头的包,你完全不需要写全这个前缀。例如:

collection.mutable.HashMap

上述代码和以下写法一样好:

scala.collection.mutable. HashMap

本文来源http://www.cnblogs.com/sunddenly/p/4436897.html

版权声明:欢迎转载,希望在你转载的同时,添加原文地址,谢谢配合

时间: 2024-10-03 21:54:37

Scala详解---------包和引用的相关文章

Scala详解---------数组相关操作

Scala中提供了一种数据结构-数组,其中存储相同类型的元素的固定大小的连续集合.数组用于存储数据的集合,但它往往是更加有用认为数组作为相同类型的变量的集合. 取替声明单个变量,如number0, number1, ..., 和number99,声明一个数组变量,如号码和使用numbers[0],numbers[1],...,numbers[99]表示单个变量.本教程介绍了如何声明数组变量,创建数组和使用索引的过程变量数组.数组的第一个元素的索引是数字0和最后一个元素的索引为元素的总数减去1.

GDT,LDT,GDTR,LDTR 详解,包你理解透彻(转)

引自:http://www.techbulo.com/708.html 一.引入 保护模式下的段寄存器 由 16位的选择器 与 64位的段描述符寄存器 构成 段描述符寄存器: 存储段描述符 选择器:存储段描述符的索引 段寄存器 PS:原先实模式下的各个段寄存器作为保护模式下的段选择器,80486中有6个(即CS,SS,DS,ES,FS,GS)80位的段寄存器.由选择器CS对应表示的段仍为代码段,选择器SS对应表示的段仍为堆栈段. 二.详解 先说明一下概念 (1)全局描述符表GDT(Global

Scala详解---------数组、元组、映射

一.数组 1.定长数组 声明数组的两种形式: 声明指定长度的数组 val 数组名= new Array[类型](数组长度) 提供数组初始值的数组,无需new关键字 Scala声明数组时,需要带有Array类名,且使用 () 来指明长度或提供初始值序列. 在JVM中,Scala的Array以Java数组的方式实现.如arr在JVM中的类型对应java.lang.String[],charArr对应char[]. 2.变长数组 ArrayBuffer,全称scala.collection.mutab

Scala详解

1       快速入门... 4 1.1             分号... 4 1.2             常变量声明... 4 1.2.1         val常量... 4 1.2.2         var变量... 4 1.2.3         类型推导... 5 1.2.4         函数编程风格... 5 1.3             Range. 5 1.4             定义函数... 6 1.5             while.if6 1.6 

Scala详解---------对象

Scala中的对象 摘要: 在本篇中,你将会学到何时使用Scala的object语法结构.在你需要某个类的单个实例时,或者想为其他值或函数找一个可以挂靠的地方时,你就会用到它.本篇的要点包括: 1. 用对象作为单例或存放工具方法 2. 类可以拥有-个同名的伴生对象 3. 对象可以扩展类或特质 4. 对象的apply方法通常用来构造伴生类的新实例 5. 如果不想显式定义main方法,可以用扩展App特质的对象 6. 你可以通过扩展Enumeration对象来实现枚举 单例对象 Scala没有静态方

Scala详解---------控制结构和函数

条件表达式: Scala的if else语法结构和Java的一样,不过,Scala的if else表达式有值,这个值就是跟在if或者else后面的表达式的值. 例如: if(x>0) 0 else 1 该表达式的值就是0或者1,具体的根据x值判断. 可以将if else表达式的值赋值给变量: val s=if(x>0) 0 else 1 这个跟如下语句一致: if(x>) s=0 else s=1 当然,第一种写法更好,它可以用来初始化一个val(常量),而第二种s必须是var(变量).

Scala详解--------基础知识详解

Chapter1 1.Scala解释器 启动Scala解释器的方法如下: 自己总结的: 1.打开执行命令栏WIN+R  ,输入cmd,在命令行上输入Scala等待启动如下 如上面所示即可启动Scala 2.使用bin内部的启动脚本 找到你所安装Scala的目录,并在Scala的bin文件夹中找到scala.bat文件,打开即可. 以上是我知道的打开方式,另外,可以使用eclipseEE进行安装插件,进行使用,具体的使用情况可以参考上一篇文章. 下面来测试一下Scala编译器的效果吧 测试成功,说

Scala详解---------快速入门Scala

我无可救药地成为了Scala的超级粉丝.在我使用Scala开发项目以及编写框架后,它就仿佛凝聚成为一个巨大的黑洞,吸引力使我不得不飞向它,以至于开始背离Java.固然Java 8为Java阵营增添了一丝亮色,却是望眼欲穿,千呼万唤始出来.而Scala程序员,却早就在享受lambda.高阶函数.trait.隐式转换等带来的福利了. Java像是一头史前巨兽,它在OO的方向上几乎走到了极致,硬将它拉入FP阵营,确乎有些强人所难了.而Scala则不,因为它的诞生就是OO与FP的混血儿--完美的基因融合

Scala详解---------Scala是什么?可伸展的语言!

Scala是什么 Scala语言的名称来自于"可伸展的语言".之所以这样命名,是因为他被设计成随着使用者的需求而成长.你可以把Scala应用在很大范围的编程任务上,从写个小脚本到建立个大系统. 51CTO编辑推荐:Scala编程语言专题 Scala是很容易进入的语言.它跑在标准的Java平台上,可以与所有的Java库实现无缝交互.它也是用来编写脚本把Java控件链在一起的很好的语言.但是用它来建立大系统和可重用控件的架构将更能够发挥它的力量. 从技术层面上来说,Scala是一种把面向对