[英]Validation usage with |@| in Scalaz
I have Map[String,String]
of configuration values. 我有配置值的Map[String,String]
。 I want to extract a series of keys and provide meaningful error messages if any of them are missing. 我想提取一系列密钥,并提供有意义的错误消息,如果缺少任何密钥。 For example: 例如:
val a = Map("url"->"http://example.com", "user"->"bob", "password"->"12345")
Say I want to transform this into a case class: 假设我想将其转换为案例类:
case class HttpConnectionParams(url:String, user:String, password: String)
Now, I can simply use a for loop to extract the values: 现在,我可以简单地使用for循环来提取值:
for(url <- a.get("url");
user <- a.get("user");
password <- a.get("password")) yield {
HttpConnectionParams(url,user,password)
}
To get an Option[HttpConnectionParams]
. 获取Option[HttpConnectionParams]
。 This is nice and clean, except if I get a None
then I don't know what was missing. 这很干净,除非我得到一个None
然后我不知道缺少什么。 I'd like to provide that information. 我想提供这些信息。
Enter scalaz. 输入scalaz。 I'm using version 7.1.3. 我使用的是7.1.3版本。
From what I've been able to put together (a good reference is here ) I can use disjunctions: 从我能够组合起来( 这里有一个很好的参考)我可以使用析取:
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)
}
This is nice because now I get an error message, but this is railway oriented because it stops at the first failure. 这很好,因为现在我收到一条错误信息,但这是铁路导向的,因为它在第一次失败时停止。 What if I want to get all of the errors? 如果我想获得所有错误怎么办? Let's use validation and the applicative builder (aka "|@|"): 让我们使用验证和applicative builder(又名“| @ |”):
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)
}
This does what I expect, but I have some questions about the usage: 这符合我的期望,但我对使用方法有一些疑问:
import scalaz._
somehow didn't work for me.[1] import scalaz._
不知怎的对我不起作用。[1] How can I figure this out from the API docs? 我怎样才能从API文档中找到答案? [1] After much consternation I arrived at this set of imports for the applicative use-case. [1]经过多次惊愕,我得到了针对应用用例的这组导入。 Hopefully this helps somebody: 希望这有助于某人:
import scalaz.std.string._
import scalaz.syntax.std.option._
import scalaz.syntax.apply._
import scalaz.Success
import scalaz.Failure
You can do this a little more nicely by defining a helper method and skipping the .tupled
step by using .apply
: 你可以通过定义一个帮助器方法并使用.apply
跳过.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)
Also, please don't be ashamed to use import scalaz._, Scalaz._
. 另外,请不要羞于使用import scalaz._, Scalaz._
。 We all do it and it's just fine in the vast majority of cases. 我们都这样做,在绝大多数情况下都很好。 You can always go back and refine your imports later. 您可以随时返回并优化您的导入。 I also still stand by this answer I wrote years ago—you shouldn't feel like you need to have a comprehensive understanding of Scalaz (or cats) in order to be able to use pieces of it effectively. 我还坚持多年前写的这个答案 - 你不应该觉得你需要全面了解Scalaz(或猫)才能有效地使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.