2016-06-21 55 views
1

我正在经历scala的不耐烦,并遇到了我似乎无法理解的多条件循环的例子。具有多个条件的Scala循环 - 返回什么?

来自Java背景我正在将这些循环看作嵌套for循环。但为什么第一个返回collection和第二个String

scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar 
res11: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p) 

scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar 
res12: String = HIeflmlmop 
+0

请参阅http://docs.scala-lang.org/tutorials/FAQ/yield.html –

+0

简而言之,在for-comprehensions中,返回类型由第一个集合或可穿越)使用。 –

回答

4

用于推导只是语法糖和被翻译成调用map,flatMap,withFilter(如果不使用收益,也是foreach)。

for { 
    i <- 0 to 1 
    c <- "Hello" 
} yield (i + c).toChar 

相当于

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

这些变压器的方式,他们回到同一类型的集合,他们被称为上,或最接近的一个定义,例如这里Range成为一个Vector结束,因为你不能有Range包含任意字符。从String开始,您仍然可以使用String

一般而言,您可以这样想:理解创建的结果类型与第一个生成器的类型(或最接近的可能)相同。

例如,如果你把字符串转换成Set

for { 
    c <- "Hello".toSet[Char] 
    i <- 0 to 1 
} yield (i + c).toChar 

你会得到一个Set回来,因为它是一个集它将不包含重复这样的结果是不同的。 Set(e, f, m, I, l, p, H, o)

类型的确定方式涉及CanBuildFrom特征。你可以阅读更多关于它是如何工作的here

+0

另一种方法来做你的例子'Set':'{_ < - Set(''); c < - “你好”; i < - 0到1}产生(i + c).toChar'。不知道这是更好的方式,但有时它看起来更干净。 –

1

使用阶2.11.8 REPL为desugar(印刷后压片,取出<pressed TAB here>):

scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar //print<pressed TAB here> 

scala.Predef.intWrapper(0).to(1).flatMap[Char, scala.collection.immutable.IndexedSeq[Char]](((i: Int) => 
    scala.Predef.augmentString(scala.Predef.augmentString("Hello"). 
     map[Char, String](((c: Char) => i.+(c).toChar))(scala.Predef.StringCanBuildFrom))))(scala.collection.immutable.IndexedSeq.canBuildFrom[Char]) // : scala.collection.immutable.IndexedSeq[Char] 

scala> for (i <- 0 to 1; c <- "Hello") yield (i + c).toChar //print 
res4: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p) 

scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar //print<pressed TAB here> 

scala.Predef.augmentString("Hello").flatMap[Char, String](((c: Char) => scala.Predef.intWrapper(0).to(1). 
     map[Char, scala.collection.immutable.IndexedSeq[Char]](((i: Int) => i.+(c).toChar))(scala.collection.immutable.IndexedSeq.canBuildFrom[Char])))(scala.Predef.StringCanBuildFrom) // : String 

scala> for (c <- "Hello"; i <- 0 to 1) yield (i + c).toChar //print 
res5: String = HIeflmlmop 

更可读的输出:

scala> (0 to 1).flatMap(i => "Hello".map(c => (i+c).toChar)) 
res14: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p) 

scala> "Hello".flatMap(c => (0 to 1).map(i => (i + c).toChar)) 
res15: String = HIeflmlmop