Scala中的for推導式

for循環與if語句是各個編程語言中最常用的控制結構語句。在Scala中,for循環的特性被成爲for推導式或者for表達式。

1. for循環的普通用法


我們現在以一個基本的for表達式開始,逐漸熟悉for推導式的各種用法:

val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane", "ortuguese Water Dog")

for (breed <- dogBreeds)
  println(breed)

Scala中for表達式寫法與Java等其他語言有實質的區別,在Scala中引入生成器表達式(breed <- dogBreeds)的概念.生成器表達式會基於集合生成單獨的數值,然後進行遍歷。而Java的寫法卻需要定義一個循環變量或者使用JDK1.5以後提供的forEach寫法,如:

List<String> dogBreeds = new ArrayList<String>();
dogBreeds.add("Doberman");
dogBreeds.add("Yorkshire Terrier");
dogBreeds.add("Dachshund");
dogBreeds.add("Scottish Terrier");
dogBreeds.add("Great Dane");
dogBreeds.add("ortuguese Water Dog");

//普通for循環
for(int i = 0 ; i < dogBreeds.size() ; i++){
    System.out.println(dogBreeds.get(i));
}

//foreach循環方式
for(String dog : dogBreeds){
    System.out.println(dog);
}

從上述代碼中我們可以看出Scala代碼的簡潔,同樣的功能,Scala的代碼量將減小60+%。對於這一點,後續的代碼也會有明顯的例證。

2. for保護式,過濾數據


在實際開發中,我們經常會在for循環中增加一些過濾條件以方便處理數據或者縮小處理範圍,如上例,我們可能只是關注包含“Terrier”的Dog,這樣,我們的代碼將改爲:

List<String> dogBreeds = new ArrayList<String>();
dogBreeds.add("Doberman");
dogBreeds.add("Yorkshire Terrier");
dogBreeds.add("Dachshund");
dogBreeds.add("Scottish Terrier");
dogBreeds.add("Great Dane");
dogBreeds.add("ortuguese Water Dog");

//普通for循環
for(int i = 0 ; i < dogBreeds.size() ; i++){    
    String dog = dogBreeds.get(i);
    if(dog.contains("Terrier"){
        System.out.println(dogBreeds.get(i));
    }
}

//foreach循環方式
for(String dog : dogBreeds){
    if(dog.contains("Terrier"){
        System.out.println(dogBreeds.get(i));
    }
}

在Java中,我們是在for循環體中寫if表達式,用於過濾並處理數據。但是在Scala中,保護式可以更簡單的完成類似功能。保護式主要是用於篩選出我們希望保留的元素

val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")

for (breed <- dogBreeds if breed.contains("Terrier"))   println(breed)

上述代碼雖然與Java實現相同功能,但是Scala更加簡潔,而且代碼可讀性更強。而且我們在開發中要重點注意的是:Scala保護式不是寫在For循環體中,而是直接寫在For表達式中。 Scala也支持在for循環中添加多個表達式。例如,我們可能不需要處理“Scottish Terrier”,則可以寫爲:

val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")

for (breed <- dogBreeds if breed.contains("Terrier") if !breed.startsWith("Yorkshire")) println(breed)

for (breed <- dogBreeds
  if breed.contains("Terrier") && !breed.startsWith("Yorkshire")
) println(breed)

3. Scala的Yielding


前邊所有實例代碼都是在For循環中直接處理數據,我們使用for循環還有一個作用就是縮小處理數據的範圍或者獲取一個滿足條件的數據集。在Java中,如果實現這個功能,我們可能會對數據集循環,並且新建一個List用於存放滿足條件的數據,最後將新建的LIst對象反回給調用者,這裏就不用Java代碼來表示。在Scala中,我們使用yield關鍵字就可以在for表達式中生成新的集合。

val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
val filteredBreeds = for {breed <- dogBreeds 
if breed.contains("Terrier") && !breed.startsWith("Yorkshire")
} yield breed

每次執行for循環表達式時,過濾後的結果將生成bread值。而yield將這些結果累積起來,並且將這些集合賦值給fileteredBreeds對象。代碼執行結果時值包含一個元素的List元素,唯一的元素值是“Scottish Terrier”。

需要注意事項

  • 在執行for循環時,for表達式即可以使用小括號(圓括號),也可以使用花括號。其執行結果是一樣的。
  • for-yield表達式中,Scala會根據源的類型進行類型推導,生成的新表達式與原表達式類型相同。由於dogBreeds類型爲List[String],則僧成的filteredBreeds的類型也爲List[String]。

1. 擴展作用域與值定義


擴展作用域:Scala的for推導式中的最初部分定義值,並可以在後邊表達式中使用該值。如下所示:

val dogBreeds = List("Doberman", "Yorkshire Terrier", "Dachshund","Scottish Terrier", "Great Dane","Portuguese Water Dog")
for {
  breed <- dogBreeds
  upcasedBreed = breed.toUpperCase()
} println(upcasedBreed)

在上述代碼中,upcasedBreed的值是不可以變的,但是這樣的語法是不需要使用val關鍵字進行限定。

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