Scala迭代一组对象

时间:2014-08-01 09:56:43

标签: scala scalaz

我有一个密封的特性,由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
  }

有更好的方法吗?我可以申请的任何建议或模式吗?

1 个答案:

答案 0 :(得分:3)

我们将定义成功结果=结果正常失败结果=结果不正常

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

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

然后objects的类型为Array[MyTrait]

接下来,我们必须迭代这个数组 但是,即使之前的mapisResultOk(),只需在此数组上调用false即可继续映射。 因此,我们将使用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,并且4 + 100 = 104>将在takeWhile()中删除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.headOption不为空,

Some(fail's first element)将返回fail,否则为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)
}