scala:将错误添加到错误列表的惯用和功能方式 [英] scala: idiomatic and functional way to add errors to a list of errors
问题描述
我有以下验证方法:
$ $ 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 useValidation
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屋!