collectFirst 中的 partialFunction
partialFunction in collectFirst
我有一些对象的序列,我想收集第一个
另一个函数 returns Some()
的元素
现在,我的代码是这样工作的:
mySeq.collectFirst{
case elem if doSmth(elem).nonEmpty =>
(doSmth(elem).get, elem)
}
有没有办法:
重构它不调用doSmth两次?
更改此代码以记录 smth 以防 doSmth returns None
res.match {
case Some(v) => v
case None => log.info("Searching further...")//partial function doesn't match
}
我想说,主要问题是 - 是否可以创建一个匹配所有情况的 PartialFunction,但对于某些情况我们确实会产生一些副作用(在这种情况下是日志消息)并明确说明它不匹配?
编辑:
我想知道,为什么下面的代码会在我 运行 测试时抛出错误(虽然不是编译错误)
mySeq.collectFirst{
case elem =>
val r: Option[Int] = doSmth(elem)
r match {
case Some(res) => res
}
}
是的,可能有一种方法可以不调用 doSmth
两次并记录空值,但这看起来很难看(你必须明确地子类化 PartialFunction
,拼出 isDefined
,并有一个 var
成员来保存结果)。
总的来说,这不是 collectFirst
的好用例。只是做这样的事情:
mySeq
.view
.map(doSmth)
.flatMap {
case None =>
log("nope")
None
case x => x
}.headOption
或者,如果您像我一样,更喜欢将一系列简短的转换链接在一起形成一个整体函数,那么这里有一个奇特的方法:
mySeq
.view
.map(doSmth)
.map(_.toRight(println("searching")))
.collectFirst { case Right(x) => x }
您可以为此使用自定义模式匹配器。这是一个具有 unapply
方法的对象,可用于模式匹配。
此代码将执行与原始代码相同的操作,但只会调用 doSmth
一次:
object MatchSomething {
def unapply[T](elem: T): Option[(String, T)] =
doSmth(elem).map(r => (r, elem))
}
mySeq.collectFirst {
case MatchSomething((smth, elem)) =>
(smth, elem)
}
您可以在 unapply
方法中记录失败的匹配:
object MatchSomething {
def unapply[T](elem: T): Option[(String, T)] =
doSmth(elem) match {
case Some(r) =>
Some((r, elem))
case None =>
println(s"$elem did not match, searching further")
None
}
}
我有一些对象的序列,我想收集第一个 另一个函数 returns Some()
的元素现在,我的代码是这样工作的:
mySeq.collectFirst{
case elem if doSmth(elem).nonEmpty =>
(doSmth(elem).get, elem)
}
有没有办法:
重构它不调用doSmth两次?
更改此代码以记录 smth 以防 doSmth returns None
res.match {
case Some(v) => v
case None => log.info("Searching further...")//partial function doesn't match
}
我想说,主要问题是 - 是否可以创建一个匹配所有情况的 PartialFunction,但对于某些情况我们确实会产生一些副作用(在这种情况下是日志消息)并明确说明它不匹配?
编辑:
我想知道,为什么下面的代码会在我 运行 测试时抛出错误(虽然不是编译错误)
mySeq.collectFirst{
case elem =>
val r: Option[Int] = doSmth(elem)
r match {
case Some(res) => res
}
}
是的,可能有一种方法可以不调用 doSmth
两次并记录空值,但这看起来很难看(你必须明确地子类化 PartialFunction
,拼出 isDefined
,并有一个 var
成员来保存结果)。
总的来说,这不是 collectFirst
的好用例。只是做这样的事情:
mySeq
.view
.map(doSmth)
.flatMap {
case None =>
log("nope")
None
case x => x
}.headOption
或者,如果您像我一样,更喜欢将一系列简短的转换链接在一起形成一个整体函数,那么这里有一个奇特的方法:
mySeq
.view
.map(doSmth)
.map(_.toRight(println("searching")))
.collectFirst { case Right(x) => x }
您可以为此使用自定义模式匹配器。这是一个具有 unapply
方法的对象,可用于模式匹配。
此代码将执行与原始代码相同的操作,但只会调用 doSmth
一次:
object MatchSomething {
def unapply[T](elem: T): Option[(String, T)] =
doSmth(elem).map(r => (r, elem))
}
mySeq.collectFirst {
case MatchSomething((smth, elem)) =>
(smth, elem)
}
您可以在 unapply
方法中记录失败的匹配:
object MatchSomething {
def unapply[T](elem: T): Option[(String, T)] =
doSmth(elem) match {
case Some(r) =>
Some((r, elem))
case None =>
println(s"$elem did not match, searching further")
None
}
}