scala - 用于理解的模式匹配分配如何转化为 monadic 操作?

标签 scala syntactic-sugar for-comprehension collect

我熟悉Scala的for的概念理解只是一元操作( mapwithFilterforeachflatMap )的语法糖,脱糖在 this popular answer 中有描述.
通过这种逻辑,我惊讶地发现,当使用模式匹配作为 for 的赋值部分的一部分时理解,没有MatchError当模式与元素不匹配时抛出。相反,不匹配的元素被过滤掉:

case class Account(id: String, role: String)
val accounts = Set(Account("a", "ADMIN"), Account("b", "USER"), Account("c", "ADMIN"), Account("d", "USER"), Account("e", "USER"))

val adminIds = for (Account(id, "ADMIN") <- accounts) yield id
// Set("a", "c") (no MatchError on Account("b", "USER")!
我原以为这种理解会转化为这样的东西:
val adminIds = accounts.map { case Account(id, "ADMIN") => id }

// or maybe
val adminIds = accounts.map { account =>
  val Account(id, "ADMIN") = account
  id
}

但当然那些会抛出 MatchError .相反,它似乎与此更相似:
val adminIds = accounts.collect { case Account(id, "ADMIN") => id }
但是,我从未见过任何提及 for 的内容。领悟脱糖成collect称呼。
那么这是如何在引擎盖下完成的呢?

最佳答案

添加我的答案,最初是作为评论发布的。
在幕后,你的理解被翻译成:

val adminIds = accounts.withFilter {
  case Account(id: String, "ADMIN") => true;
  case _ => false
}.map({
  case Account(id: String, "ADMIN") => id
})
换句话说,它使用 withFilter .
总结自 linked answer , withFilter在 scala 2.8 中引入并适用于严格集合(如 List ,而不是像 Stream 这样的非严格集合。)它不是返回一个新的、过滤的集合,而是按需过滤。
这就是为什么您没有注意到 MatchError运行代码时。

关于scala - 用于理解的模式匹配分配如何转化为 monadic 操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69572368/

相关文章:

scala - 在并行计算中正确使用 future

scala - 无法在抽象类中导入案例类

Scala for comprehension - yield w/a complex filter

scala - 我如何更改 Apache Spark 上的数据位置

ruby - 在 Ruby 中评估许多 bool 表达式,如 Array#join

c# - 使用 GetRange 获取所有剩余项目

haskell - Haskell 脱糖有什么好处?

scala - 用于理解 if 守卫

scala - 如何表达[42 | x == y] 与理解?

scala - 在SBT中进行交叉构建时设置唯一的快照版本