使用| @ |进行验证在斯卡拉兹

时间:2015-09-02 16:45:57

标签: scala scalaz

背景

我有Map[String,String]个配置值。我想提取一系列密钥,并提供有意义的错误消息,如果缺少任何密钥。例如:

val a = Map("url"->"http://example.com", "user"->"bob", "password"->"12345")

说我想将其转换为案例类:

case class HttpConnectionParams(url:String, user:String, password: String)

现在,我可以简单地使用for循环来提取值:

for(url <- a.get("url"); 
    user <- a.get("user"); 
    password <- a.get("password")) yield {  
  HttpConnectionParams(url,user,password) 
}

获得Option[HttpConnectionParams]。这很干净,除非我得到None,否则我不知道遗漏了什么。我想提供这些信息。

使用Scalaz进行验证

输入scalaz。我使用的是7.1.3版本。

从我能够组合起来(一个很好的参考是here)我可以使用析取:

for(url <- a.get("url") \/> "Url must be supplied"; 
    user <- a.get("user") \/> "Username must be supplied"; 
    password <- a.get("password") \/> "Password must be supplied") yield {  
  HttpConnectionParams(url,user,password) 
}

这很好,因为现在我收到一条错误消息,但这是railway oriented,因为它在第一次失败时停止。如果我想获得所有错误怎么办?让我们使用验证和应用程序构建器(又名&#34; | @ |&#34;):

val result = a.get("url").toSuccess("Url must be supplied")    |@|
             a.get("username").toSuccess("Username must be supplied") |@|
             a.get("password").toSuccess("Password must be supplied")

result.tupled match {
  case Success((url,user,password)) => HttpConnectionParams(url,user,password)
  case Failure(m) => println("There was a failure"+m)
}

问题

这符合我的期望,但我对使用方法有疑问:

  • 对于这个用例,是否有一个易于使用的替代scalaz?如果我不这样做,我宁愿不打开潘多拉的盒子并介绍scalaz。
  • 我不想使用scalaz的一个原因是,如果你不像我一样了解整个框架,那么要弄清楚要做什么真的很难。例如,使上述代码工作所需的隐含列表是什么? import scalaz._某种方式对我不起作用。[1]我怎样才能从API文档中找到答案?
  • 是否有更简洁的方式来表达验证用例?我偶然发现了,直到我到达了一些有效的东西,我不知道是否还有其他更好的方法可以在scalaz中做同样的事情。

[1]经过多次惊愕,我得到了针对应用用例的这组导入。希望这有助于某人:

import scalaz.std.string._
import scalaz.syntax.std.option._
import scalaz.syntax.apply._
import scalaz.Success
import scalaz.Failure

1 个答案:

答案 0 :(得分:13)

通过使用.tupled定义辅助方法并跳过.apply步骤,您可以更好地完成此操作:

import scalaz._, Scalaz._

def lookup[K, V](m: Map[K, V], k: K, message: String): ValidationNel[String, V] =
  m.get(k).toSuccess(NonEmptyList(message))

val validated: ValidationNel[String, HttpConnectionParams] = (
  lookup(a, "url", "Url must be supplied") |@|
  lookup(a, "username", "Username must be supplied") |@|
  lookup(a, "password", "Password must be supplied")
)(HttpConnectionParams.apply)

另外,请不要羞于使用import scalaz._, Scalaz._。我们都这样做,在绝大多数情况下它都很好。您可以随时返回并优化您的导入。我还在几年前写过this answer - 我不应该对Scalaz(或猫)有全面的了解,以便能够有效地使用它。