在下面的代码中,版本 1 给出了正确的结果。我对 V2 做了一个小改动。 None 值消失了,这很好,因为 For Expression 就是这样工作的。但是,V2 中的 yield 输出不再遵循 myList.lift() 返回的数据类型(如在 V1 中一样)的原因是什么?
val myList = List(12, 34, "ABC")
版本 1
for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
版本 2
for {
i <- (0 to 3).toList
x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
最佳答案
第一种情况的脱糖:
// desugar for comprehension:
(0 to 3).toList.map(
i => myList.lift(i))
对第二种情况进行脱糖:
// desugar for comprehension:
(0 to 3).toList.flatMap(
i => myList.lift(i).map(
x => x))
// remove .map(x => x):
(0 to 3).toList.flatMap(
i => myList.lift(i))
// desugar flatMap:
(0 to 3).toList.map(
i => myList.lift(i)).flatten
第二种情况简化为第一种情况,末尾有 .flatten
,这解释了结果的差异:res2 = res1.flatten
。
Scala 可以将 Option
视为一个序列:
Some(foo) --> Seq(foo)
None --> Seq()
.flatten
只是将序列序列展平。
如果你对类型感到好奇:
scala.collection.Seq.flatten
要求“内部”类型隐式转换为 GenTraversableOnce[T]
Option[T]
到 Iterable[T]
的全局隐式转换Iterable[T] <: GenTraversableOnce[T]
<-
中的 x <- myList.lift(i)
不只是将变量分配给一个值,它“从”myList.lift(i)
中“获取一个值”。当您从 Option[T]
中“获取一个值”时,您将获得 foo
的 Some(foo)
而 None
没有任何内容“一无所获”意味着 yield
根本不运行 None
,因此当 i = 3
时,“迭代”的结果中没有显示任何内容。
如果您对这个为 Seq
、 Option
和 Scala 中的许多其他类型定义的“获取值”概念感到好奇,那么它是为任何 Monad 定义的。
https://stackoverflow.com/questions/38820577/