我经历了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 :(得分:4)
对于理解只是语法糖,并被转换为map
,flatMap
,withFilter
(如果你不使用yield)的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
并且## 39; t 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
答案 1 :(得分:1)
对desugar使用scala 2.11.8 repl(打印后按Tab键,删除<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