繁体   English   中英

Scala遍历一组对象

[英]Scala iterate over a set of objects

我有一个由3个对象实现的密封特征

sealed trait MyTrait {
...
}
object A extends MyTrait { ... }
object B extends MyTrait { ... }
object C extends MyTrait { ... }

我正在使用Scalaz的验证机制,其中对象A,B和C的apply方法返回经过验证的类型。 对象A,B和C确实包含一些逻辑,我想按顺序应用此逻辑,即,我要首先应用A并检查A的结果是什么,并基于此结果,确定我是否要调用B或只是返回验证的结果。 我想重复一遍,直到我按下C,然后我才返回由于调用C而得到的任何结果。

当前,我有一个静态方法,首先调用A,将A的结果传递给实用程序方法,然后检查结果,然后调用B。

  def apply(request: Request): Validated[Result] = {
    val vResultA = run(request, A)
    val vResultB = if (isResultOk(vResultA)) run(request, B) else vResultA
    if (isResultOk(vResultB)) run(request, C) else vResultB
  }

有一个更好的方法吗? 有什么建议或模式可以应用吗?

我们将定义成功的结果=合格的结果失败的结果=不合格的结果

首先, ABC都是扩展MyTrait对象。 因此,可以将它们分组为Array或MyTrait列表。

val objects = Array(A, B, C) /* You can use List instead if you want. */

那么objects的类型是Array[MyTrait]

接下来,我们必须迭代该数组。
但是,即使先前的isResultOk()false ,仅在此Array上调用map也会继续进行映射。
因此,我们将使用Stream而不是Array

让我们看看如果满足某些条件,使用Stream如何停止调用map

Array(1, 2, 3, 4, 5).map(i => {
    println(i)
    i + 100
  }).takeWhile(_ <= 103).foreach(println(_))

上面代码的输出将是:

1
2
3
4
5
101
102
103

因此, map()结束,然后takeWhile()结束takeWhile()不会影响对map()调用。
但是,如果我们在Stream上执行相同的操作,

Array(1, 2, 3, 4, 5).toStream.map(i => {
    println(i)
    i + 100
  }).takeWhile(_ <= 103).foreach(println(_))

输出将是:

1
101
2
102
3
103
4

所以调用将是map() -> takeWhile() -> foreach() -> map() -> takeWhile() -> ...
最后,将打印4,并且将在takeWhile()剪切4 + 100 = 104> 103。
以下元素将不再被访问。

那么,我们必须使用takeWhile吗?

objects.toStream.map(run(request, _)).takeWhile(isResultOk(_))

这将消除失败的结果,即使如果发生失败,我们需要第一个失败的结果。
(即,如果有任何不正确的结果,将会造成问题。)

相反的函数dropWhile()呢?

objects.toStream.map(run(request, _)).dropWhile(isResultOk(_))

即使所有结果都成功,这也会摆脱所有成功的结果。
(即,如果所有结果都正确,这将造成问题。)

因此,我们将使用span()
c.span(p) = (c.takeWhile(p), c.dropWhile(p))
我们将测试是否存在不正确的结果。
如果结果不正确,则我们将返回第一个此类结果。
否则,我们将返回最后一个确定的结果。

val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
fail.headOption.getOrElse(succ.last)

如果fail为空,则fail.headOption将返回Some(fail's first element) ,否则返回None

综上所述,

val objects = Array(A, B, C)

def apply(request: Request): Validated[Result] = {
  val (succ, fail) = objects.toStream.map(run(request, _)).span(isResultOk(_))
  fail.headOption.getOrElse(succ.last)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM