在下面的代码中,版本1给出了正确的结果。我在V2中做了一个小变化。无值已经消失,这是好的,因为这是For Expression的工作方式。但是什么原因导致V2中的yield输出不再尊重myList.lift()返回的数据类型,这是一个Option(如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)
答案 0 :(得分:6)
贬低第一个案例:
// 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定义的。
答案 1 :(得分:3)
如果你为了理解而去糖
版本1
List(0, 1, 2, 3).map({ i =>
myList.lift(i)
})
版本2
List(0, 1, 2, 3).flatMap({ i =>
myList.lift(i).map({ x => x })
})
V2中的yield输出不再尊重myList.lift()返回的数据类型的原因是什么
yield
对List.lift
的输出无效:
myList.lift(i)
返回Option[Any]
myList.lift(i).map({ x => x })
返回Option[Any]
flatMap
将Option[Any]
展平为Any
(通过放弃None
并取消包裹Some(a: Any) => a
)