我很难理解Scala中使用for-compression的机制。 例如,如果我有
val x = for {
i <- Option(1)
j <- Option(2)
k <- Option(3)
} yield (i,j,k)
x
是x: Option[(Int, Int, Int)] = Some((1,2,3))
。
但是,例如,如果组件中的至少一个为“无”,则
val x = for {
i <- Option(1)
j <- Option(2)
k <- None
} yield (i,j,k)
然后x
是x: Option[(Int, Int, Nothing)] = None
,而我实际上希望看到的是:x: Option[(Int, Int, Nothing)] = Some((1,2,None))
。
我检查了FAQ from Scala official documentation,其中明确指出for-comprehension
是flatmap
和map
的组合。但是我仍然很难理解x
是None
。
我认为我错过了一些关于flatmap
和map
区别的重要概念。
答案 0 :(得分:5)
第一个具有理解力的“减糖”:
val x = Option(1).flatMap(
i => Option(2).flatMap(
j => Option(3).map(
k => (i, j, k)
)
)
)
如您所见-第一个Option使用获取其值(如果存在)并返回3元组(使用第二个Option的类似操作)的函数进行平面映射。无论该函数是什么-整个表达式的形式均为:
val x = Option(1).flatMap(f)
现在,如果我们将Option(1)
替换为None
(就像您在第二个表达式中所做的那样),我们显然会得到None
:
val x = None.flatMap(f) // None, for any f
您期望的结果(Some((None, 2, 3))
不太有用-因为对于不同的输入它会有不同类型:会是(Option[Int], Int, Int)
吗?还是(Int, Int, Int)
?还是(Option[Int], Option[Int], Option[Int])
?实际上,(None, 2, 3)
,(1, None, 3)
和(1, 2, None)
的唯一常见类型是不太有用的(Any, Any, Any)
。