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

Validation usage with |@| in Scalaz

背景

我有 Map[String,String] 个配置值。我想提取一系列密钥并在其中任何一个丢失时提供有意义的错误消息。例如:

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

说我想把这个转化成一个案例class:

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,因为它会在第一次失败时停止。如果我想得到所有的错误怎么办?让我们使用验证和应用程序构建器(又名“|@|”):

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)
}

问题

这符合我的预期,但我对用法有一些疑问:

[1] 在大吃一惊之后,我得出了这组用于应用用例的导入。希望这对某人有所帮助:

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

您可以通过定义辅助方法并使用 .apply:

跳过 .tupled 步骤来更好地完成此操作
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(或猫)有全面的了解才能有效地使用它。