2016-09-12 40 views
0

我是斯卡拉的新手,我正在通過Cay Horstmann的斯卡拉爲Impatient工作。它順利,直到我得到了理解,並碰到了這種略帶神祕的通道(2.6,先進的循環和悟):斯卡拉發電機的順序「理解」影響答案

[開始報價]

生成的收集與兼容第一發電機。

for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar 
    // Yields "HIeflmlmop" 
for (i <- 0 to 1; c <- "Hello") yield (c + i).toChar 
    // Yields Vector('H', 'e', 'l', 'l', 'o', 'I', 'f', 'm', 'm', 'p') 

[結束報價]

事實上,在REPL運行此,我看到的是,第一代碼段的結果的類型爲字符串,和第二代碼段的類型是scala.collection.immutable。 IndexedSeq [字符]。

爲什麼類型不同?我想我理解第二行代碼,但我不明白爲什麼第一行不具有類型scala.collection.immutable.IndexedSeq [Char]。得到一個字符串而不是一個Vector有什麼魔力?作者認爲「與第一臺發電機兼容」是什麼意思?

回答

4

flatMapmap都試圖在可能的情況下構建相同類型的對象。第一個例子是有效:

"Hello".flatMap { c => (0 to 1).map { i => (c + i).toChar } } 

,因爲你在呼喚String#flatMapStringOps#flatMap是精確的),它會嘗試建立String,這是可能的,因爲內部集合返回Char個集合(嘗試刪除toChar和你會看到非常不同的東西)。

在第二個例子:

(0 to 1).flatMap { i => "Hello".map { c => yield (c + i).toChar }} 

這是不可能產生一個有效的Range,所以Range#flatMap回落到Vector

另一個有趣的例子:

Map(1 -> 2, 3 -> 4).map(_._1) //> List(1, 3) 

通常Map#map會嘗試生成Map,但由於我們沒有對是不可能的,所以它回落到List

UPDATE

如果你想產生與默認不同的東西,你甚至可以使用這個技巧(例如我要生成的Char秒的列表,而不是):

for { 
    _ <- List(None) // List type doesn't matter 
    c <- "Hello" 
    i <- 0 to 1 
} yield (c + i).toChar //> List(H, I, e, f, l, m, l, m, o, p) 
0

您使用用於第一發生器的集合是如描述用於從爲表達而操作翻譯的類Scala Documentation

Scala的「爲內涵」是用於組合物語法糖使用foreach,map,flatMap,filter或withFilter進行多個操作。 Scala實際上將for-expression轉換爲對這些方法的調用,所以提供它們的任何類或它們的子集都可以用於理解。

2

要知道爲什麼:

$ scalam -Xprint:typer 
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92). 
Type in expressions for evaluation. Or try :help. 

scala> for (c <- "Hello"; i <- 0 to 1) yield (c + i).toChar 
[[syntax trees at end of      typer]] // <console> 
val res0: String = scala.Predef.augmentString("Hello").flatMap[Char, String](((c: Char) => scala.Predef.intWrapper(0).to(1).map[Char, scala.collection.immutable.IndexedSeq[Char]](((i: Int) => c.+(i).toChar))(immutable.this.IndexedSeq.canBuildFrom[Char])))(scala.Predef.StringCanBuildFrom); 

StringCanBuildFrom建立字符串,當然。

這個問題有很多重複,因爲每個人都很神祕。