繁体   English   中英

scala:将错误添加到错误列表的惯用和功能方法

[英]scala: idiomatic and functional way to add errors to a list of errors

我有以下验证方法:

def validate(wine: Wine): List[Error] = {

  var errors = List[Error]()

  if (Validate.isEmptyWord(wine.name)) {
    errors ::= ValidationError("name", "Name not specified")
  } else {
    if (isDuplicate(wine, "name")) {
      errors ::= ValidationError("name", "There already exists a wine with the name '%s'".format(wine.name))
    }
  }

  if (Validate.isEmptyWord(wine.grapes)) {
    errors ::= ValidationError("grapes", "Grapes not specified")
  }

  if (Validate.isEmptyWord(wine.country)) {
    errors ::= ValidationError("country", "Country not specified")
  }

  // more stuff like this and finnally
  errors.reverse
}

你明白了

你将如何修改它以避免var List [Error]并使其更具功能性?

Scalaz提供了一个Validation类,可以很容易地解决这类问题。 这个Stack Overflow答案中有一个更详细的如何使用Validation例子,但我也会在这里给出一个草图,说明它在你的情况下是如何工作的。 我将假设以下设置:

case class Wine(name: String, grapes: String, country: String)
case class ValidationError(name: String, msg: String)

现在我们可以编写几种验证方法(注意我使用的是Scalaz 7):

import scalaz._, Scalaz._

def checkNonempty(v: String, name: String, msg: String) =
  if (v.nonEmpty) v.successNel else ValidationError(name, msg).failNel

def checkDuplicate(v: String, name: String, msg: String) =
  if (true) v.successNel else ValidationError(name, msg).failNel

当然,您应该在最后一行添加自己的复制检查。 然后我们可以将它们包装在一起:

def createWine(name: String, grape: String, country: String) = (
  checkNonempty(name, "name", "Name not specified").flatMap(_ =>
    checkDuplicate(name, "name",
      "There already exists a wine with the name '%s'".format(name)
    )
  ) |@|
  checkNonempty(grape, "grape", "Grape not specified") |@|
  checkNonempty(country, "country", "Country not specified")
)(Wine.apply)

现在,如果我们写这样的东西:

val result: ValidationNEL[ValidationError, Wine] = createWine(
  "Whatever Estates", "Whatever Grape", "U.S."
)

我们将获得成功价值:

Success(Wine(Whatever Estates,Whatever Grape,U.S.))

但是如果我们给它无效的输入:

val result: ValidationNEL[ValidationError, Wine] = createWine(
  "", "Some Grape", ""
)

我们将获得累积错误的列表:

Failure(
  NonEmptyList(
    ValidationError(name,Name not specified),
    ValidationError(country,Country not specified)
  )
)

当然,你也可以推出自己的验证逻辑,但是如果你做了很多这样的事情,使用像Scalaz这样的库可能是值得的。

编写isX方法以返回Option[Error]而不是Boolean ,然后

List(
  Validate.isEmptyWord(wine.name, "name", "Name not specified").
  orElse( Validate.isDuplicate(wine.name, "name", "There already exists...") ),
  Validate.isEmptyWord(wine.grapes, "grapes", "Grapes not specified"),
  ...
).flatten

你会有错误的。 此外,您还可以删除大量其他重复项(例如,如果它始终为"x", "X not specified" ,则可以提供"x"并将其余部分填入isEmptyWord )。

暂无
暂无

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

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