Scala for the Impatients---(7)Packages and Imports

Packages

A package can be defined in multiple files. For example

//Employee.scala
package com {
    package horstmann {
        package impatient {
            class Employee
            ...
}
    }
        }  

and

//Manager.scala
package com {
    package horstmann {
        package impatient {
            class Manager
            ...
}
}
}    

Multiple packages can be in a single file. For example

\\Employee.scala
package
com { package horstmann { package impatient { class Employee ... } } } package org { package bigjava { class Counter ... } }

Note: There is no enforced relationship between the directory of the source file and the package. You don’t have to put Employee.scala and Manager.scala into a com/horstmann/impatient directory.

Scope Rules

(1)Let's look at this example

package com {
    package horstmann {
        object Utils {
            def percentOf(value: Double, rate: Double) = value * rate / 100
            ...
        }
        package impatient {
            class Employee {
                ...
                def giveRaise(rate: scala.Double) {
                    salary += Utils.percentOf(salary, rate)
                 }
            }
        }
    }
}

Note the Utils.percentOf qualifier. Here the class Employee is in the impatient package which, combined with Utils, is in the horstmann package. So everything in the parent package is in scope.

(2)the scala package is always imported. For example

package com {
package horstmann {
package impatient {
class Manager {
val subordinates = new collection.mutable.ArrayBuffer[Employee]
...
}
}
}
}

Therefore, the collection package is actually scala.collection.mutable.ArrayBuffer. But this omitting can cause a problem. Suppose that we, in a new file, add a subpackage collection in the parent package horstmann, then the tree structure is like:

                              |----impatient--->Manager

com---horstmann---

                              |----collection---child-->Boy

Where collection.mutable.ArrayBuffer[Employee] in the class Manager will never compile! Because it will not look for scala.collection, but only look for com.horstmann.collection.mutable, there is no such mutable package, only a package named child. To solve this conflict, Scala introduces chained package clauses.

Chained Package Clauses

A package clause can contain a “chain,” or path segment, for example:

package com.horstmann.impatient {
// Members of com and com.horstmann are not visible here
package people {
class Person
...
}
}

Such a clause limits the visible members. Now a com.horstmann.collection package would no longer be accessible as collection.

Top-of-File Notation

Instead of the nested notation that we have used up to now, you can have package clauses at the top of the file, without braces. For example

package com.horstmann.impatient
package people
class Person
...

This is equivalent to

package com.horstmann.impatient {
package people {
class Person
...
// Until the end of the file
}
}

Note that in the example above, everything in the file belongs to the package com.horstmann.impatient.people , but the package com.horstmann.impatient has also been opened up so you can refer to its contents.

Package Objects

A package can contain classes, objects, and traits, but not the definitions of functions or variables. That’s an unfortunate  limitation of the Java virtual machine. It would make more sense to add utility functions or constants to a package than to some Utils object. Package objects address this limitation. 

Every package can have one package object. You define it in the parent package, and it has the same name as the child package. For example,

package com.horstmann.impatient
    package object people {
        val defaultName = "John Q. Public"
    }
    package people {
        class Person {
            var name = defaultName // A constant from the package
... }
} ... }

Elsewhere it is accessible as com.horstmann.impatient.people.defaultName. Behind the scenes, the package object gets compiled into a JVM class with static methods and fields(here it is defaultName).  It is a good idea to use the same naming scheme for source files. Put the package object into a file com/horstmann/impatient/people/package.scala . That way, anyone who wants to add functions or variables to a package can find the package object easily.

Package Visibility

In Java, a class member that isn't declared as public/private/protected is visible in the package containing the class.

In Scala, you can achieve this with qualifiers. The following method is visible in its own package:

package com.horstmann.impatient.people
class Person {
private[people] def description = "A person with name " + name
...
}

You can extend the visibility to an enclosing package:

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

Imports

There is a point that Java doesn't have is that Scala can import all members of a class or object. Like

import java.awt.Color._
val c1 = RED // Color.RED
val c2 = decode("#ff0000") // Color.decode

Note that imports can be anywhere. The scope of the import statement extends until the end of the enclosing block. For example,

class Manager {
import scala.collection.mutable._
val subordinates = new ArrayBuffer[Employee]
...
}

By putting the imports where they are needed, you can greatly reduce the potential for conflicts.

Renaming and Hiding Members

If you want to import a few members from a package, use a selector like this:

import java.awt.{Color, Font}

The selector syntax lets you rename members:

import java.util.{HashMap => JavaHashMap}
import scala.collection.mutable._

Now JavaHashMap is a java.util.HashMap and plain HashMap is a scala.collection.mutable.HashMap .

The selector HashMap => _ hides a member instead of renaming it. This is only useful if you import others:

import java.util.{HashMap => _, _}
import scala.collection.mutable._

Now HashMap unambiguously refers to scala.collection.mutable.HashMap since java.util.HashMap is hidden.

Implicit Imports

Every Scala program implicitly starts with

import java.lang._
import scala._
import Predef._

 

posted on 2016-09-16 15:45  chaseblack  阅读(190)  评论(0编辑  收藏  举报

导航