11-包和引入

前言

這裏介紹在Scala中,包和引入的相關操作。
會與Java作對比。

1. 將代碼放入包中

如果你看過前面的章節會知道,所有的示例代碼中都是從object 對象開始。
這裏,使用包的形式。
如:

package gyt.navigation
class Navigator

如Java一樣,如果你的包名是網站,建議倒着寫。
另外一種類型C#的命名空間的做法,稱爲打包。如:

package gyt.navigation {
  class Navigator
}

打包是一個更加通用的表示法,讓我們可以在一個文件裏包含多個內容。如,將源代碼和測試代碼放在一起:

package gyt {
  package navigation {
    // 位於 gyt.navigation 中
    class Navigator
    package tests {
      // 位於 gyt.navigation.tests 中
      class Tests
    }
  }
}

2. 對相關代碼的精簡訪問

將代碼按照包層次劃分以後,不僅有助於瀏覽代碼,同時告訴編譯器,同一個包中的代碼之間存在某種相關性。在同一個包中訪問代碼時,允許使用簡短的,不帶限定前綴的名稱。
如:

package gyt {
  package navigation {
    class Navigator {
      // 簡短
      val map = new StarMap
    }
    class StarMap
  }
  class Ship {
    // 加上包名
    val nav = new navigation.Navigator
  }
  package fleets {
    class Fleet {
      // 屬於同一級包
      def addShip() = {
        new Ship
      }
    }
  }
}

如果不在同一級包,不能使用簡短訪問,如:

package gyt {
  class Ship
}
package gyt2.fleets {
  class Fleet {
    def addShip() = {
      // 無法通過編譯
      new Ship
    }
  }
}

不再同一級包,需要使用包名,如:

package gyt {
  class Ship
}
package gyt2.fleets {
  class Fleet {
    def addShip() = {
      // 能夠通過編譯
      new gyt.Ship
    }
  }
}

位於不同文件,使用_root_,因爲,所有的頂層包都被當做_root_的成員,寫法如:
gyt 與 gyt3 都屬於各自文件的頂層包時:
在這裏插入圖片描述

3. 引入

引入關鍵字import,被引入的包和它的成員可以簡單使用,而不需要限定名稱。
準備一個待引入的包:

package gyt
abstract class Fruit(
  val name: String,
  val color: String
)
object Fruits {
  object Apple extends Fruit("apple", "red")
  object Orange extends Fruit("orange", "orange")
  object Pear extends Fruit("pear", "yellowish")
  val menu = List(Apple, Orange, Pear)
}

引入語句示例:

// 引入Fruit
import gyt.Fruit

// 引入gyt的所有成員
import gyt._

// 引入Fruits的所有成員
import gyt.Fruits._

另外,Scala的引入可以出現在代碼的任何地方。

Scala的靈活引入:

與Java相比,Scala的import 子句要靈活得多。主要的區別有三點:
在Scala中,引入可以:

  • 出現在任何位置
  • 引用對象(不論是單例還是常規對象),而不只是包
  • 讓你重命名並隱藏某些被引入的成員

Scala引入可以重命名或隱藏指定的成員。做法是包括在花括號內的引入選擇器子句中。如:

// 只引入Fruits對象中的Apple和Orange
import Fruits.{Apple, Orange}

// 只引入Fruits對象中的Apple和Orange, 並對Apple重命名爲NewAp
import Fruits.{Apple=>NewAp, Orange}

// 引入Fruits的所有成員, 相當於import Fruits._
import Fruits.{_}

// 引入Fruits的所有成員, 並對Apple重命名爲NewAp
import Fruits.{Apple=>NewAp,_}

// 引入Fruits的所有成員, 除了Apple
import Fruits.{Apple=>_,_}

因此,可以總結引入選擇器:

  • 一個簡答的x。
  • 一個重命名x=>y。
  • 一個隱藏子句x=>_。
  • 捕獲所有x=>_。

4. 隱式引入

Scala對每個程序都隱式地添加了一些引入。每個".scala"源文件的頂部都添加了如下三個引入子句:

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

所以,能夠直接使用java.lang、scala、Predef 包中的對象。
注意,引入的順序,如果出現同名的對象,後面的引入會遮擋前面的引入。 就像內部的同名變量會遮擋外部的同名變量。

5. 訪問修飾符

Java中有四種訪問修飾符,而Scala中有三種:private、protected、公共的。Scala與Java大體保持一致,但也有一些重要區別。

  • 私有成員
    私有成員只在含定義的類或對象的內部可見,與Java相同。但是,有一個區別,如:
class Outer {
  class Inner {
    private def f() = println("hello")
    class InnerMore {
      f() // OK
    }
  }
  (new Inner).f() //錯誤, 無法訪問
}

也就是說,Scala無法從外部類訪問內部類的私有成員,而Java可以。

  • 受保護的成員
    更Java相比,Scala對proteced成員的訪問也更加嚴格。在Scala中,protected的成員只能從定義該成員的子類訪問。而Java允許同一個包內的其他類訪問這個類的受保護的成員。
    Scala提供了另一種方式到達這個效果,即:修飾符[限定詞]
    如:
class father {
  protected def f() = println("hello")
}
class sun extends father {
  f() // OK
}
class other {
  f() // 錯誤
}
  • 公共成員
    Scala沒有專門的修飾符修飾公共成員:任何沒有被標記爲private和protected的成員都是公共的。公共成員可以從任何位置訪問。

前面提到了,Scala可以使用修飾符[限定詞] 的格式更加細粒度的修飾成員。
例如:
源代碼:

解釋:
在這裏插入圖片描述
值得一提的是,private[this]的定義,只能在包含該定義的同一個對象訪問。該定義稱爲對象私有
也就是說,對它的訪問必須來自對象內部,並且爲同一個實例。
如果不是同一個實例,則訪問不被允許,如:

// speed 的修飾符爲private[this]
val other = new Navigator
other.speed	// 不能被編譯, 不是同一個實例

可見性和伴生對象

在Java中,靜態成員和實例成員同屬於一個類,因此訪問修飾符對它們的應用方式是統一的。
Scala沒有靜態成員,而使用伴生對象來承載只存在一次的成員。
伴生類和伴生對象無論各自的成員是公共的、protected、private都可以互相訪問。
不過,伴生對象中,protected 成員沒有意義,因爲伴生對象沒有子類。

6. 包對象

目前爲止,能夠往包中添加類、特質、孤立對象等。這些都是放在包內頂層最常見的定義。任何你能夠放在類級別的定義,都能夠放在包級別。如在包級別放一個函數,作爲整個包都可以使用的助手函數。
具體的做法是把定義放在包對象。每個包都允許一個包對象,任何放在包對象的定義都會被當作包本身的成員。
示例:
gyt/package.scala
注意:package + object

package object gyt {
  def f() = {
    println("hello")
  }
}

gyt/Test.scala

package gyt

object Test {
  def main(args: Array[String]): Unit = {
    f()
  }
}

包對象會被編譯成名爲package.class的類文件,所以,該文件位於它增強的包的對象的目錄下。習慣將包對象的源代碼放在包名目錄下的package.scala中。
運行:
需要構建一個Scala項目,這裏使用IDEA。
在這裏插入圖片描述

後續篇章

12-樣例類和模式匹配

完!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章