for comprehensions 中的模式匹配分配如何转化为一元操作?
How do pattern match assignments in for comprehensions translate into monadic operations?
我很熟悉 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
调用的情况。
那么这是如何在幕后完成的?
如果您将该代码放入像 Intellij 和 desugar 这样的 IDE 中,您将得到类似这样的东西
val adminIds: Set[String] = accounts.withFilter { case Account(id: String, "ADMIN") => true; case _ => false }.map({ case Account(id: String, "ADMIN") => id })
不是来电收款
添加我的答案,该答案最初作为评论发布。
在幕后,您的理解翻译为:
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 的 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
调用的情况。
那么这是如何在幕后完成的?
如果您将该代码放入像 Intellij 和 desugar 这样的 IDE 中,您将得到类似这样的东西
val adminIds: Set[String] = accounts.withFilter { case Account(id: String, "ADMIN") => true; case _ => false }.map({ case Account(id: String, "ADMIN") => id })
不是来电收款
添加我的答案,该答案最初作为评论发布。
在幕后,您的理解翻译为:
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
的原因。