为什么For Comprehension生成器抑制Option类型?

Pol*_*ase 1 scala for-comprehension

在下面的代码中,版本1给出了正确的结果.我在V2中做了一个小变化.无值已经消失,这是好的,因为这是For Expression的工作方式.但是什么原因导致V2中的yield输出不再尊重myList.lift()返回的数据类型,这是一个Option(如V1所示)?

val myList = List(12, 34, "ABC")
Run Code Online (Sandbox Code Playgroud)

版本1

for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
Run Code Online (Sandbox Code Playgroud)

版本2

for { 
  i <- (0 to 3).toList 
  x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
Run Code Online (Sandbox Code Playgroud)

Gor*_*son 7

贬低第一个案例:

// desugar for comprehension:
(0 to 3).toList.map(
  i => myList.lift(i))
Run Code Online (Sandbox Code Playgroud)

贬低第二种情况:

// 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
Run Code Online (Sandbox Code Playgroud)

第二种情况简化为第一种情况,最后是a .flatten,这解释了结果的不同:res2 = res1.flatten.

究竟发生了什么?

Scala可以Option视为一个序列:

Some(foo) --> Seq(foo)
None      --> Seq()
Run Code Online (Sandbox Code Playgroud)

.flatten只是使序列序列变平.

如果你对这些类型感到好奇:

  • scala.collection.Seq.flatten 要求'inner'类型具有隐式转换 GenTraversableOnce[T]
  • 有一个全球性的隐式转换从Option[T]Iterable[T]
  • Iterable[T] <: GenTraversableOnce[T]

什么< - 意味着呢?

<-x <- myList.lift(i)没有按"吨只是一个变量分配给一个值,'得到一个值超出’ myList.lift(i)当你'得到一个值超出’了Option[T],你得到fooSome(foo)并没有什么的None.'得到什么’是指yield没有按" T运行对于a来说None,所以没有任何东西出现在"迭代"的结果中i = 3.

如果您想了解这个"获取值出来的",也就是为定义的概念Seq,Option和许多其他类型在Scala中,它是任何单子定义.