[英]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
}
有一个更好的方法吗? 有什么建议或模式可以应用吗?
我们将定义成功的结果=合格的结果 , 失败的结果=不合格的结果 。
首先, A
, B
和C
都是扩展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.