我有以下for-yield循环,它接受一个布尔值,应该产生Some(string)或None,具体取决于boolean:
val theBoolean = false
val x: Option[String] =
for {
theArg <- theBoolean
} yield {
if (theArg) {
"abc"
} else {
None
}
}
如果theBoolean
实际上是像false
这样的布尔值,那么效果很好。但是,如果我想传递Option[Boolean]
:
val theBoolean = Some(false)
似乎Scala自动将Some()包装器应用于None返回 - 我得到一个投诉&#34;类型Option [Serializable]的表达式不符合预期类型Option [String]&# 34; (无是Serializable)。虽然收益率非常高,但是相同的字符串返回(它不会成为选项[Option [String]]
在这种情况下如何返回无?
答案 0 :(得分:14)
for-comprehension只是一系列flatMap
,map
和filter
的语法糖。
那么,让你的代码去掉你的代码:
val theBoolean = Some(false)
val x = theBoolean.map { theArg =>
if (theArg) {
"abc"
} else {
None
}
}
正如您所看到的,您只是映射Option
的值,因此您将返回Some(abc)
,Some(None)
或{{1} (如果None
已经theBoolean
)。
None
和None
的最低常见类型为"abc"
,这就是为什么java.Serializable
的类型被推断为x
的原因,这与Option[Serializable]
毫无意义。
可能的解决方案是:
使用Option[Any]
flatMap
甚至更短
theBoolean.flatMap(theArg => if (theArg) Some("abc") else None)
过滤和映射
theBoolean.flatMap(if (_) Some("abc") else None)
我使用theBoolean.withFilter(identity).map(_ => "abc")
的地方,因为您正在测试值本身。
很明显,你总是可以利用for-comprehension提供的句法糖,虽然它在这种情况下并没有真正有所作为
identity
答案 1 :(得分:1)
你是对的,yield
块中的所有内容都包含在一个选项中(这就是选项的理解方式)。一般来说,for-comprehensions描述了在monad中可以找到的内容,在其上可以找到for-comprehension,但最终结果(对于yield
块之外的世界)仍然是相同类型的monad(例如Option,Try或List)。
更一般地说:有很多关于monad是什么的描述。你可以假设monad是臭名昭着的Schrödinger盒子,你正在思考隐藏在那里的猫会发生什么,但所有这些仍然是可能的,因为盒子还没有打开。
实现目标的可能方式:
val theBoolean = false
val x: Option[String] =
for {
theArg <- theBoolean if theArg
} yield {
"abc"
}
答案 2 :(得分:1)
而不是理解它听起来像你想要一个flatMap而不是理解。
scala> Some(false).flatMap(if (_) Some("abc") else None)
res4: Option[String] = None