我熟悉Scala的for
的概念理解只是一元操作( map
、 withFilter
、 foreach
和 flatMap
)的语法糖,脱糖在 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/