博客
关于我
Scalaz(20)-Monad: Validation-Applicative版本的Either
阅读量:463 次
发布时间:2019-03-06

本文共 3567 字,大约阅读时间需要 11 分钟。

Scalaz中的Validation:深入理解其功能与应用

Scalaz中的Validation是一个强大的功能,用于处理数据验证和错误处理。它在很多方面与 Scala的标准库/(即Either)有相似之处,但又有显著的区别。Validation不仅提供了基本的验证功能,还通过其Applicative特性,允许同时处理多个Validation,并返回多个异常信息。以下将深入探讨Validation的核心功能、与/的区别以及其实际应用场景。

Validation的核心概念

Validation在Scalaz中定义为:

sealed abstract class Validation[+E, +A] extends Product with Serializable {  // 其他定义已省略...  def isSuccess: Boolean = this match {    case Success(_) => true    case Failure(_) => false  }  // 其他方法已省略...}

Validation有两个状态:Success和Failure。Success表示验证成功,返回一个值;Failure表示验证失败,返回一个异常信息。与/(Either)相比,Validation的主要特点在于它支持多个异常信息的返回。

Validation与/的区别

虽然Validation和/在某些方面非常相似,但它们在处理多个异常信息时有显著差异。与/不同之处在于,Validation通过其Applicative特性,可以在同一个操作中处理多个Validation,并返回多个异常信息。

操作符API

Validation提供了丰富的操作符API,包括:

  • orElse:如果当前Validation是成功,则返回当前Validation;如果失败,则返回另一个Validation。
  • swap:交换Validation的状态,即将Success转换为Failure,反之亦然。
  • ap:应用函数在当前Validation的成功路径上,同时处理可能的错误。

这些操作符使得Validation在处理复杂的验证逻辑时非常灵活。

Validation的状态定义

Validation的两个状态定义如下:

final case class Success[A](a: A) extends Validation[Nothing, A]final case class Failure[E](e: E) extends Validation[E, Nothing]
  • Success表示验证成功,携带一个值。
  • Failure表示验证失败,携带一个异常值。

这些状态定义使得Validation能够方便地处理成功和失败两种情况。

Validation的Monad特性

Validation是一个Monad,它支持在for-comprehension中实现 Failure立即退出的功能。例如:

for {  a <- Success(3)  b <- Success(2)} yield a + b

上述代码返回一个Success(5)的Validation。

如果其中任何一个步骤返回Failure,则整个Validation也会返回Failure。

注入方法

Scalaz为Validation提供了丰富的注入方法,例如:

  • success:创建一个成功的Validation。
  • failure:创建一个失败的Validation。
  • successNel:创建一个携带NonEmptyList的成功Validation。
  • failureNel:创建一个携带NonEmptyList的失败Validation。

这些方法使得开发者能够更方便地构建Validation实例。

例子:同时处理多个Validation

假设我们需要同时验证几个值,并返回所有异常信息,可以使用Validation的组合操作符|@|

((3.success : Validation[String, Int]) |@| ("oh, error1! ".failure : Validation[String, Int]) |@| (2.success : Validation[String, Int]) |@| ("oh, error2 again!".failure : Validation[String, Int])) {_ + _ + _ + _}

上述代码将返回一个Failure,携带所有异常信息。例如:

Failure("oh, error1! oh, error2 again!")

如果需要将异常信息存储在NonEmptyList中,可以使用failureNel方法:

((3.successNel : ValidationNel[String, Int]) |@| ("oh, error1! ".failureNel : ValidationNel[String, Int]) |@| (2.successNel : ValidationNel[String, Int]) |@| ("oh, error2 again!".failureNel : ValidationNel[String, Int])) {_ + _ + _ + _}

上述代码将返回一个Failure,携带所有异常信息:

Failure(NonEmptyList("oh, error1!", "oh, error2 again!"))

NonEmptyList的使用

NonEmptyList是Scalaz中用于表示不为空列表的数据结构。它可以与Validation结合使用,方便地将异常信息存储和处理。

例如:

val nel = 2 :@: 4 :@: 3.wrapNel

上述代码将返回一个NonEmptyList,包含元素2、4和3。

如果需要将其转换为标准的List,可以使用list方法:

nel.list

这将返回一个标准的List[2, 4, 3]。

Validation的flatMap方法

尽管Validation支持flatMap方法,但它已经被弃用。用户被鼓励使用Scalaz的标准库/或直接使用Validation的其他方法。例如,可以使用ap方法来处理多个Validation。

deprecated警告

@deprecated("flatMap does not accumulate errors, use `scalaz.\/` or `import scalaz.Validation.FlatMap._` instead", "7.1")@inline implicit def ValidationFlatMapDeprecated[E, A](d: Validation[E, A]): ValidationFlatMap[E, A] = new ValidationFlatMap(d)

用户被建议使用Scalaz的标准库/来处理错误积累问题。

Validation的Applicative特性

Validation实现了Applicative功能,通过ap方法可以在成功路径上应用函数,并处理失败路径上的异常。例如:

def ap[EE: Semigroup[EE], B](x: => Validation[EE, A => B])(implicit E: Semigroup[EE]): Validation[EE, B] = (this, x) match {  case (Success(a), Success(f)) => Success(f(a))  case (e @ Failure(_), Success(_)) => e  case (Success(_), e @ Failure(_)) => e  case (Failure(e1), Failure(e2)) => Failure(E.append(e2, e1))}

上述方法允许开发者在Validation的成功路径上应用函数,并将多个异常信息合并到一个Failure中。

总结

Validation是Scalaz中处理数据验证和错误处理的强大工具。它通过其Applicative特性,支持同时处理多个Validation,并返回多个异常信息。与/相比,Validation的主要优势在于其更灵活的错误处理能力。通过合理使用Validation及其注入方法,开发者可以构建更高效、更健壮的错误处理逻辑。

转载地址:http://wfefz.baihongyu.com/

你可能感兴趣的文章
Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
查看>>
MySQL 是如何加锁的?
查看>>
MySQL 是怎样运行的 - InnoDB数据页结构
查看>>
mysql 更新子表_mysql 在update中实现子查询的方式
查看>>
MySQL 有什么优点?
查看>>
mysql 权限整理记录
查看>>
mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
查看>>
MYSQL 查看最大连接数和修改最大连接数
查看>>
MySQL 查看有哪些表
查看>>
mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
查看>>
MySql 查询以逗号分隔的字符串的方法(正则)
查看>>
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
查看>>
mysql 查询数据库所有表的字段信息
查看>>
【Java基础】什么是面向对象?
查看>>
mysql 查询,正数降序排序,负数升序排序
查看>>
MySQL 树形结构 根据指定节点 获取其下属的所有子节点(包含路径上的枝干节点和叶子节点)...
查看>>
mysql 死锁 Deadlock found when trying to get lock; try restarting transaction
查看>>
mysql 死锁(先delete 后insert)日志分析
查看>>
MySQL 死锁了,怎么办?
查看>>
MySQL 深度分页性能急剧下降,该如何优化?
查看>>