scala:将错误添加到错误列表的惯用和功能方式 [英] scala: idiomatic and functional way to add errors to a list of errors

查看:94
本文介绍了scala:将错误添加到错误列表的惯用和功能方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下验证方法:

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

var errors = List [Error]()

if(Validate.isEmptyWord(wine.name)){
errors :: = ValidationError(name,名称未指定)
}其他{
if(isDuplicate(wine,name)){
errors :: = ValidationError(name,There is a wine with the格式(wine.name))
}
}

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

国家,国家没有指定)
}

//更多类似于这个和finnally
errors.reverse
}

您有这个想法



您如何修改它以避免var List [错误]并使其更加实用?

解方案

Scalaz 提供了验证类,它使得这种问题的功能方法非常简单。在这个Stack Overflow答案中有一个更详细的例子,说明如何使用 Validation 一个>,但我也会在这里给出一个草图来展示它如何在你的情况下工作。我假定以下设置:

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

现在我们可以写几个验证方法(请注意,我使用Scalaz 7):
$ b $ pre $ 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

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

$ $ p $ $ $ c $ def createWine(name:String,grape:String,country:String)=(
checkNonempty(name,name,Name not specified)。flatMap(_ =>
checkDuplicate(name,name,
格式(名称)

)| @ |
checkNonempty(葡萄,grape,Grape not specified)| @ |
checkNonempty(country ,country,Country not specified)
)(Wine.apply)

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

  val结果:ValidationNEL [ValidationError,Wine] = createWine(
Estates,任何葡萄,美国

我们会得到成功价值:

 成功(葡萄酒(无论葡萄酒,美国葡萄酒))



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

  val结果:ValidationNEL [ValidationError,Wine] =创建葡萄酒(
,一些葡萄,

我们将得到一个累积错误列表:

 失败(
NonEmptyList(
ValidationError(name ,未指定名称),
ValidationError(国家,国家未指定)


当然,您也可以推出自己的验证逻辑,但是如果您正在做这类事情,使用像Scalaz这样的库可能会遇到麻烦。


I have the following validation method:

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
}

You get the idea

How would you modify it to avoid the var List[Error] and make it more functional?

解决方案

Scalaz provides a Validation class that makes a functional approach to this kind of problem very easy. There's a more detailed example of how to use Validation in this Stack Overflow answer, but I'll also give a sketch here to show how it might work in your situation. I'll assume the following setup:

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

Now we can write a couple of validation methods (note that I'm using 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

Where of course you should add your own duplication checking to the last line. Then we can wrap it all together:

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)

Now if we write something like this:

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

We'll get a success value:

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

But if we give it invalid input:

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

We'll get a list of the accumulated errors:

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

You could also roll your own validation logic, of course, but using a library like Scalaz is probably worth the trouble if you're doing much of this kind of thing.

这篇关于scala:将错误添加到错误列表的惯用和功能方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆