如果我传入一个选项,Scala for-yield是否可以返回?

时间:2014-11-05 00:52:01

标签: scala

我有以下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]]

在这种情况下如何返回无?

3 个答案:

答案 0 :(得分:14)

for-comprehension只是一系列flatMapmapfilter的语法糖。 那么,让你的代码去掉你的代码:

val theBoolean = Some(false)

val x = theBoolean.map { theArg =>
  if (theArg) {
    "abc"
  } else {
    None
  }
}

正如您所看到的,您只是映射Option的值,因此您将返回Some(abc)Some(None)或{{1} (如果None已经theBoolean)。

NoneNone的最低常见类型为"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