简体   繁体   English

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

[英]Validation usage with |@| in Scalaz

Background 背景

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. 我想提供这些信息。

Validation with Scalaz 使用Scalaz验证

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

Questions 问题

This does what I expect, but I have some questions about the usage: 这符合我的期望,但我对使用方法有一些疑问:

  • Is there an easy to use alternative to scalaz for this use-case? 对于这个用例,是否有一个易于使用的替代scalaz? I'd prefer to not open pandora's box and introduce scalaz if I don't have to. 如果我不需要,我宁愿不打开潘多拉的盒子并引入scalaz。
  • One reason I'd like to not use scalaz is that it's really really hard to figure out what to do if you don't, like me, know the entire framework. 我不想使用scalaz的一个原因是,如果你不像我一样知道整个框架,那真的很难弄清楚要做什么。 For example, what is the list of implicits that you need to get the above code to work? 例如,使上述代码工作所需的隐含列表是什么? import scalaz._ somehow didn't work for me.[1] import scalaz._不知怎的对我不起作用。[1] How can I figure this out from the API docs? 我怎样才能从API文档中找到答案?
  • Is there a more succinct way to express the validation use-case? 是否有更简洁的方式来表达验证用例? I stumbled my way through until I arrived at something that worked and I have no idea if there are other, better ways of doing the same thing in scalaz. 我偶然发现了,直到我到达了一些有用的东西,我不知道是否还有其他更好的方法在scalaz中做同样的事情。

[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM