跳转到内容

Scala/包

来自维基教科书,开放世界中的开放书籍

包是一个组织单元,可以包含类、对象和其他包等实体。包含在给定包中的实体属于该包的命名空间。

请注意,以下示例可能无法在 Scala REPL 中运行。

包可以在源文件的开头声明

package geometry

class Rectangle

在第一行,关键字“package”后跟名称“geometry”声明了一个名为“geometry”的包。所有后续实体都属于该包。在第三行,定义了一个名为“Rectangle”的类,由于它在“geometry”包中声明,因此它的完整标识符为“geometry.Rectangle”。

可以通过在每个包之间插入“.”来声明多个嵌套包

package org.transport.vehicles

class Car

在第一行,声明了嵌套包“org”、“transport”和“vehicles”。“org”是最外层的包,“transport”是最中间的包,“vehicles”是最内层的包。在第三行,定义了一个名为“Car”的类,它的完整标识符为“org.transport.vehicles.Car”。

类似的方法是将包链接起来

package org
package transport
package vehicles

class Car

这声明了 3 个嵌套包和一个名为“Car”的类,其完整标识符为“org.transport.vehicles.Car”。

包也可以通过在包名后跟一对花括号来在源代码中的其他地方声明

package org.transport

package vehicles {
  class Car
}

package fuel {
  class Gasoline
}

第一行定义了嵌套包“org.transport”。第 3 到 5 行定义了一个属于“org.transport”的包,名为“vehicles”,它包含类“Car”。第 7 到 9 行定义了一个属于“org.transport”的包,名为“fuel”,它包含类“Gasoline”。类“Car”的完整标识符为“org.transport.vehicles.Car”,类 Gasoline 的完整标识符为“org.transport.fuel.Gasoline”。

一个命名空间中的实体通常不能直接引用另一个命名空间中的实体,除非使用完整标识符

package somePack1 {
  class SomeClass
}
package somePack2 {
  class AnotherClass {
    val a = new somePack1.SomeClass
    //ERROR: Does not compile!
    //val b = new SomeClass
  }
}

在某些情况下,不同命名空间中的实体可以在不使用完整标识符的情况下相互引用。一种情况是在引用层次结构中上层包中的实体时。规则是,对于每个嵌套声明中的最后一部分的实体,所有声明的包都可以直接引用。

package p1.p2.p3

class A

package p4 {
  class B
}

package p4 {
  package p5 {
    class C
  }

  package p5.p6 {
    class D {
      val a = new A
      val b = new B
      val c = new p5.C
      //ERROR: Does not compile!
      //val c2 = new C
    }
  }
}

在上面,声明了几层包。最底层的包“p6”包含一个名为“D”的类。对于类“D”,它的包声明可以总结为“p1.p2.p3”、“p4”和“p5.p6”。由于包“p3”、“p4”和“p6”是“D”的每个包声明的最后部分,因此所有成员都可以直接在“D”中引用。相反,在“p1”、“p2”和“p5”中的实体无法直接引用。这有助于对哪些实体可以或不能直接引用进行细粒度控制。默认方法是将包声明在一个声明中,这意味着只有当前包中的实体可以被直接引用。

下层嵌套包会覆盖上层包。这意味着在某些情况下,引用特定实体可能很困难。在这种情况下,可以使用特殊包“_root_”。所有顶级包都被视为“_root_”的成员

package tools {
  class Console
}

package carpentry {
  package tools {
    class Hammer

    package testing {
      class A {
        val console = new _root_.tools.Console
        //ERROR: Does not compile!
        //val console2 = new tools.Console
      }
    }
  }
}

在上面,从类“A”的角度来看,包“tools”指的是“carpentry.tools”包,因为它覆盖了“tools”包。为了引用最外层的“tools”包,使用了包“_root_”。

需要注意的是,不同包中的实体通常可以通过使用导入来更轻松地引用,这在Scala/Import中进行了描述。

华夏公益教科书