- Scala編程(第5版)
- (德)馬丁·奧德斯基等
- 1871字
- 2022-05-06 15:51:33
第10步 使用集和映射
由于Scala想讓你同時享有函數式和指令式編程風格的優勢,其集合類庫特意對可變和不可變的集合進行了區分。舉例來說,數組永遠是可變的;列表永遠是不可變的。Scala還提供了集(set)和映射(map)的可變和不可變的不同選擇,但使用同樣的簡稱。對集和映射而言,Scala通過不同的類繼承關系來區分可變和不可變版本。
例如,Scala的API包含了一個基礎的特質來表示集,這里的特質與Java的接口定義類似。(你將在第11章了解到更多關于特質的內容。)在此基礎上,Scala提供了兩個子特質(subtrait),一個用于表示可變集,另一個用于表示不可變集。
在圖3.2中可以看到,這3個特質都叫作Set。不過它們的完整名稱并不相同,因為它們分別位于不同的包。Scala API中具體用于表示集的類,如圖3.2中的HashSet類,分別擴展自可變或不可變的特質Set。(在Java中“實現”某個接口,而在Scala中“擴展”或“混入”特質。)因此,如果想要使用一個HashSet,則可以根據需要選擇可變或不可變的版本。創建集的默認方式如示例3.5所示。

圖3.2 Scala集的類繼承關系

示例3.5 創建、初始化并使用一個不可變集
在示例3.5的第一行,定義了一個新的名稱為jetSet的var,并將其初始化為一個包含兩個字符串——"Boeing"和"Airbus"的不可變集。由這段代碼可知,在Scala中可以像創建列表和數組那樣創建集:通過調用Set伴生對象的名稱為apply的工廠方法。在示例3.5中,實際上調用了scala.collection. immutable.Set的伴生對象的apply方法,返回了一個默認的、不可變的集的對象。Scala編譯器推斷出jetSet的類型為不可變的Set[String]。
要向集中添加新元素,可以對集調用+方法,傳入這個新元素。無論是可變的還是不可變的集,+方法都會創建并返回一個新的包含了新元素的集。在示例3.5中,處理的是一個不可變的集。可變集提供了一個實際的+=方法,而不可變集并不直接提供這個方法。
本例的第二行,即“jetSet += "Linear"”在本質上是如下代碼的簡寫:

因此,在示例3.5的第二行,實際上是將jetSet這個var重新賦值成了一個包含"Boeing"、"Airbus"和"Linear"的新集。示例3.5的最后一行打印出這個集是否包含"Cessna"。(正如你預期的那樣,它將打印false。)
如果你想要的是一個可變集,則需要做一次引入(import),如示例3.6所示。

示例3.6 創建、初始化并使用一個可變集
示例3.6的第一行引入了scala.collection.mutable。import語句允許在代碼中使用簡稱,而不是更長的完整名。這樣一來,當你在第三行用到mutable.Set的時候,編譯器就知道你指的是scala.collection.mutable. Set。在那一行,將movieSet初始化成一個新的包含字符串"Spotlight"和"Moonlight"的新的可變集。接下來的一行通過調用集的+=方法將"Parasite"添加到可變集里。前面提到過,+=實際上是一個定義在可變集上的方法。只要你想,也完全可以不用ovieSet += "Parasite"這樣的寫法,而是將其寫成movieSet.+= ("Parasite")。[8]
雖然由可變和不可變集的工廠方法生成的默認集的實現對于大多數情況來說都夠用了,但是偶爾可能也需要一類特定的集。幸運的是,語法上面并沒有大的不同。只需要簡單地引入需要的類,然后使用其伴生對象上的工廠方法即可。例如,如果你需要一個不可變的HashSet,則可以:

Scala的另一個有用的集合類是Map。與集類似,Scala也提供了映射的可變和不可變的版本,用類繼承關系來區分。如圖3.3所示,映射的類繼承關系與集的類繼承關系很像。在scala.collection包里有一個基礎的Map特質,還有兩個子特質,都叫Map,可變的那個子特質位于scala.collection. mutable,而不可變的那個子特質位于scala.collection.immutable。

圖3.3 Scala映射的類繼承關系
Map的實現,如圖3.3中的HashMap,擴展自可變或不可變的特質。與數組、列表和集類似,可以使用工廠方法來創建和初始化映射。
示例3.7展示了一個可變映射的具體例子。示例3.7的第一行引入了可變的Map特質。接下來定義了一個名稱為treasureMap的val,并初始化成一個空的,且以整數為鍵、以字符串為值的可變映射。這個映射之所以是空的,是因為執行了名稱為empty的工廠方法并指定了Int作為健類型,String作為值類型。[9]在接下來的幾行,通過->和+=方法向映射添加了鍵/值對(key/value pair)。正如前面演示過的,Scala編譯器會將二元(binary)的操作,如1 -> "Go to island.",轉換成標準的方法調用,即(1).->("Go to island.")。因此,當你寫1-> "Go to island."時,實際上是對這個值為1的整數調用->方法,傳入字符串"Go to island."。可以在Scala的任何對象上調用這個->方法,它將返回包含鍵和值兩個元素的元組。[10]然后將這個元組傳遞給treasureMap指向的那個映射對象的+=方法。最后一行將打印出treasureMap中鍵2對應的值。運行這段代碼以后,變量step2將會指向"Find big X on ground."。

示例3.7 創建、初始化并使用一個可變映射
如果你更傾向于使用不可變的映射,則不需要任何引入,因為默認的映射就是不可變的,如示例3.8所示。

示例3.8 創建、初始化并使用一個不可變映射
由于沒有顯式引入,當你在示例3.8中的第一行提到Map時,得到的是默認的那個scala.collection.immutable.Map。接下來將5組鍵/值元組傳遞給映射的工廠方法,返回一個包含了傳入的鍵/值對的不可變映射。如果運行示例3.8中的代碼,它將打印出“IV”。
- JavaScript百煉成仙
- Web應用系統開發實踐(C#)
- LabVIEW Graphical Programming Cookbook
- 編程卓越之道(卷3):軟件工程化
- ASP.NET Core 2 and Vue.js
- Python高效開發實戰:Django、Tornado、Flask、Twisted(第3版)
- Building a Quadcopter with Arduino
- 3D少兒游戲編程(原書第2版)
- 快人一步:系統性能提高之道
- Getting Started with LLVM Core Libraries
- Learning Material Design
- Mastering Android Studio 3
- Python編程入門(第3版)
- 優化驅動的設計方法
- C/C++程序設計教程