我认为您可能会从使用 Lift 的Box中受益,它具有Full
(ie Some
)、Empty
(ie None
) 和Failure
(anEmpty
以及它是空的并且可以链接的原因)。David Pollak 有一篇很好的博客文章介绍了它。简而言之,你可能会做这样的事情(未经测试):
def validate1: Box[String]
def validate2: Box[String]
def validate3: Box[String]
val validation = for (
validation1 <- validate1 ?~ "error message 1"
validation2 <- validate2 ?~ "error message 2"
validation3 <- validate3 ?~ "error message 3"
) yield "overall success message"
这并不比原始示例短,但在我看来,它更合乎逻辑,结果是在 a 中成功验证,Full
在Failure
.
但是,我们可以变得更小。首先,由于我们的验证函数 return Box[String]
,它们可以Failure
自己返回 s ,我们不需要转换Empty
为Failure
自己:
val validation = for (
validation1 <- validate1
validation2 <- validate2
validation3 <- validate3
) yield "overall success message"
但是,Box
也有一个方法,如果是,则or
返回相同,否则返回另一个。这会给我们:Box
Full
Box
val 验证 = validate1 或 validate2 或 validate3
但是,该行在第一次验证成功时停止,而不是在第一次失败时停止。制作另一种方法来做你想要的(可能称为unless
?)可能是有意义的,尽管我不能说它真的比 for 理解方法有用得多。
但是,这里有一个小库拉皮条可以做到这一点:
scala> class Unless[T](a: Box[T]) {
| def unless(b: Box[T]) = {
| if (a.isEmpty) { a }
| else b
| }
| }
defined class Unless
scala> implicit def b2U[T](b: Box[T]): Unless[T] = new Unless(b)
b2U: [T](b: net.liftweb.common.Box[T])Unless[T]
scala> val a = Full("yes")
a: net.liftweb.common.Full[java.lang.String] = Full(yes)
scala> val b = Failure("no")
b: net.liftweb.common.Failure = Failure(no,Empty,Empty)
scala> val c = Full("yes2")
c: net.liftweb.common.Full[java.lang.String] = Full(yes2)
scala> a unless b
res1: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)
scala> a unless b unless c
res2: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)
scala> a unless c unless b
res3: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty)
scala> a unless c
res4: net.liftweb.common.Box[java.lang.String] = Full(yes2)
这是基于我对 Scala 类型系统的有限理解的快速破解,您可以在以下错误中看到:
scala> b unless a
<console>:13: error: type mismatch;
found : net.liftweb.common.Full[java.lang.String]
required: net.liftweb.common.Box[T]
b unless a
^
但是,这应该足以让您走上正轨。
当然Lift ScalaDocs有更多关于Box的信息。