scala - 避免在模式匹配情况下重做不必要的计算
问题描述
这个问题是 Scala 的模式匹配语法特有的。因此,假设我有一些与此等效的代码:
def process(seq: Seq[SomeObjectType]): SomeReturnType = seq match {
case Seq() => // Return something
case s if s exists (o => o.somePropertyTest) => {
// Ok, the test is satisfied, now let's find
// that object in the sequence that satisfies
// it and do something with it
}
case _ => // Return something if no other case matches
}
现在很明显,这段代码的效率并不高,因为我检查序列中是否有一个元素满足一些测试,然后在这种情况下,我继续找到元素并使用它,这可以做一些像这样避免遍历序列两次:
def process(seq: Seq[SomeObjectType]): SomeReturnType = seq match {
case Seq() => // Return something
case s => {
val obj = s find (o => o.somePropertyTest)
if !obj.isEmpty {
// Ok, the test is satisfied, and we have
// the object that satisfies it, obj, so
// do something with it directly
} else {
// Handle the no-match case here instead
}
}
}
但这违背了模式匹配的全部目的,尤其是在我进行测试之后有多种情况时。如果测试不通过,我仍然希望执行落到下一个案例,即如果没有元素满足条件,但我也想“保留”在测试中找到的序列的元素并直接使用它案例主体,有点类似于人们可以用来@
为复杂案例命名并在其主体中使用该名称的方式。我正在尝试通过模式匹配做的事情吗?还是模式匹配太复杂而无法处理?
请注意,为清楚起见,这是一个简化的示例。在我的实际问题中,序列很长,并且对序列的每个元素的测试包括构建一个相对较大的树并检查该树是否具有某些属性,因此仅处理低效的第一个版本确实不是一个选择.
解决方案
您可以使用方法定义自定义提取器对象unapply
。限制是您不能在模式匹配中内联创建这样的对象。您必须在匹配之前显式创建它。例如:
case class Selector[T](condition: T => Boolean) {
def unapply(seq: Seq[T]): Option[T] = seq.find(condition)
}
object Selector {
// seq argument is used only to infer type `T`
def from[T](seq: Seq[T])(condition: T => Boolean): Selector[T] = Selector(condition)
}
def process(seq: Seq[SomeObjectType]): SomeReturnType = {
// Create an extractor object instance
val Select = Selector.from(seq)(_.somePropertyTest)
seq match {
case Seq() => // seq empty
case Select(o) => // found o, we can process it now
case _ => // didn't find a suitable element
}
}
推荐阅读
- intellij-idea - 在intellij中更改导入项目的默认路径
- c++ - 将整个 QAbstractTableModel 传递给 QML
- typescript - 使用 typeof 作为参数类型
- javascript - 将字符串转换为数组中的键值对
- javascript - html5 视频应该从某个时间开始并循环播放
- c - 编译linux内核时展开单个文件的宏
- python - 创建一个错误处理熊猫过滤并将值导出到Excel单元格的函数
- python - 当 python 脚本中发生故障时,管道不会失败
- salesforce - 如何在闪电组件中将base64字符串显示为pdf
- c# - 尝试保存到数据库时,列数与第 1 行的值计数不匹配