[TOC]
前言
scala中的for相比于java而言非常的靈活多變岔乔,同時(shí)功能也非常強(qiáng)大酥筝。
眾所周知,在java或者其他傳統(tǒng)的語言中重罪,大多數(shù)情況下for只是用來做循環(huán)遍歷的用途樱哼。但是在scala中for卻是有許多獨(dú)特的用法哀九。
for表達(dá)式的一般形式
for (sequence) yield expression
此處的sequence由生成器、定義搅幅、過濾器組成阅束。比如:
val list = List.range(1, 11)
val sub2 = for (i <- list; if i % 2 == 0) yield 2 * i
此處的圓括號(hào)也可以用花括號(hào)來代替:
for {
i <- list //生成器
if i % 2 == 0 //過濾器
} yield 2 * i
for表達(dá)式的轉(zhuǎn)譯
此處所說的轉(zhuǎn)譯指的是編譯器將我們所寫的for表達(dá)式中的生成器、過濾器等轉(zhuǎn)譯為等價(jià)的高階函數(shù)的過程茄唐。
帶yield的for轉(zhuǎn)譯
帶yield的for表達(dá)式都會(huì)被轉(zhuǎn)譯為高階函數(shù) map
,flatMap
,filter
的組合調(diào)用息裸。
比如:
val sub2=for {
i <- list //生成器
if i % 2 == 0 //過濾器
} yield 2 * i
將會(huì)被轉(zhuǎn)譯為:
val sub2 = list.filter(_ % 2 == 0).map(_ * 2)
不帶yield的for轉(zhuǎn)譯
不帶yield的for表達(dá)式都會(huì)被轉(zhuǎn)譯為對(duì)高階函數(shù) filter
和foreach
的組合調(diào)用。
比如:
for {
i <- list //生成器
if i % 2 == 0 //過濾器
} {
println(i * 2)
}
將會(huì)被轉(zhuǎn)譯為:
list.filter(_ % 2 == 0).foreach(i => println(i * 2))
for表達(dá)式的適用場景
對(duì)于scala本身提供的類型比如List和Array沪编,對(duì)其使用for表達(dá)式的情況很常見呼盆,但通常我們很少問為什么?
就像java中增強(qiáng)的for循環(huán)的應(yīng)用一樣:
for(String s : names){
//....
}
對(duì)java而言蚁廓,這里的names可以是什么類型访圃??相嵌?
事實(shí)上腿时,for表達(dá)式的適用場景不僅是針對(duì)于Array和List。
scala提供的其他類型比如Range饭宾、Iterator批糟、Stream、Set等一樣可以使用for表達(dá)式看铆。
比如:
for (i <- Range(1, 3))
println(i)
正是由于for表達(dá)式的轉(zhuǎn)譯僅僅依賴于 map
,flatMap
,filter
,foreach
這幾個(gè)有限數(shù)量的高階函數(shù)徽鼎。
所以for表達(dá)式的大規(guī)模的適用場景就是理所當(dāng)然的了。
一般而言弹惦,有如下規(guī)律:
假設(shè)T
為你的某種自定義類型:
- 如果T同時(shí)定義了 map , flatMap , filter , foreach
- 恭喜你否淤,T可以完美的支持for表達(dá)式的所有操作
- T只定義了map
- 可以使用帶單個(gè)生成器的for
- T定義了map和flatMap
- 可以使用帶若干個(gè)生成器的for
- T定義了foreach
- 可以使用帶若干個(gè)生成器的for
- T定義了filter
- 可以使用帶過濾器的for
此時(shí)的T的定義可能如下所示:
abstract class T[A]{
def map[B](f:A=>B):T[B]
def flatMap[B](f:A=>T[B]):T[B]
def filter(p:A=>Boolean):T[A]
def foreach(f:A=>Unit):Unit
}
例子
最后以書籍《Programming in Scala》中的一個(gè)非常經(jīng)典的例子來結(jié)尾。
題意
有一個(gè)代表書籍的內(nèi)存數(shù)據(jù)庫列表如下:
case class Book(title: String, authors: String*)
object Book {
def books: List[Book] = {
val books: List[Book] = List(
Book(
"Structure and Interpretation of Computer Programs",
"tom", "cat"), //
Book(
"Principles of Compiler Design",
"tom", "apache"), //
Book(
"The Java Language Specification",
"Gosling, James", "Joy, Bill", "Steele, Guy", "Bracha, Gilad"), //
Book(
"Programming in Modula-2",
"tom", "spark"), //
Book(
"Elements of ML Programming",
"tom", "cat") //
)
return books
}
}
要求一
找出姓"Gosling"的作者的所有書籍
val result = for {
b <- books
a <- b.authors if a.startsWith("Gosling")
} yield b.title
println(result)
要求二
找出所有書名中包含Programming的書籍的書名
val names = for (b <- books if b.title.indexOf("Programming") >= 0)
yield b
println(names)
要求三
找出寫了兩本書的作者的名字
val authors = for {
b1 <- books
b2 <- books if b1 != b2
a1 <- b1.authors
a2 <- b2.authors if a1 == a2
} yield a1
println(authors)
注意肤频,此處的結(jié)果或會(huì)重復(fù)叹括。