【问题标题】:Why doesn't this for-comprehension, starting with Option, compile in Scala? [duplicate]为什么这个从Option开始的理解不能在Scala中编译? [复制]
【发布时间】:2014-05-22 09:43:30
【问题描述】:

鉴于这些定义:

val guys = List("Albert", "Tom")
val girls = List("Mary", "Stacy", "Josie")

val optRoom: Option[String] = Some("Room 303")

这对我来说是预期的List[String]

for {
  guy <- guys
  girl <- girls
  room <- optRoom
} yield {
  s"$guy dances with $girl in $room"
}

在循环内部稍微转一下,我希望这会评估为 Option[List[String]],但它甚至无法编译:

for {
  room <- optRoom
  guy <- guys
  girl <- girls
} yield {
  s"$guy dances with $girl in $room"
}  

为什么不呢?我错过了什么? (我知道我可以将optRoot 转换为序列/列表/可迭代,但这不是我想要的)

我应该如何重写我的代码以获得Option[List[String]]

【问题讨论】:

    标签: scala for-loop monads scala-collections optional


    【解决方案1】:

    你的第二个例子相当于

    optRoom flatMap { room =>
      guys flatMap { guy =>
        girls map { girl =>
          s"$guy dances with $girl in $room"
        }
      }
    }
    

    这不起作用,因为您没有将 Option 返回到 optRoom.flatMap

    如果您想要Option[List[String]],那么您想要调用optRoom.map,而不是flatMap,因为您希望将结果包装在Option中:

    for {
      room <- optRoom
    } yield for {
      guy <- guys
      girl <- girls
    } yield {
      s"$guy dances with $girl in $room"
    }
    

    【讨论】:

    • 感谢您的回答。您说:“因为您没有将 Option 返回到 optRoom.flatMap”。有可能这样做吗?这有意义吗?
    • 如果您在optRoom 不是None 的情况下计算的结果自然是Option[something],这将是有意义的。在您的情况下,它自然是List[String]。所以你可以把它变成Some[List[String]],但这只是使用flatMap来模拟map
    【解决方案2】:

    你可以这样做:

    optRoom.map(room => for {
      guy <- guys
      girl <- girls
    } yield s"$guy dances with $girl in $room")
    

    您的第二个for 大致翻译为:

    optRoom.flatMap(room => guys.flatMap(guy => girls.map(girl => s"$guy dances with $girl in $room")))
    

    由于您有optRoom.flatMap(room =&gt; ...),因此该参数应该是来自String =&gt; Option[B] 的函数,但guys.flatMap(...) 不是Option 类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-04
      • 2011-07-08
      • 2018-01-05
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多