以下是我的用例
Config
,然后使用Cats对其进行验证。我正在使用this作为指导。我的问题是指南中给出的示例属于此类
case class Person(name: String, age: Int)
def validatePerson(name: String, age: Int): ValidationResult[Person] = {
(validateName(name),validate(age)).mapN(Person)
}
但是就我而言,我已经将配置反序列化到我的case类中(下面是一个示例),然后将其传递给我进行验证
case class Config(source: List[String], dest: List[String], extra: List[String])
def vaildateConfig(config: Config): ValidationResult[Config] = {
(validateSource(config.source), validateDestination(config.dest))
.mapN { case _ => config }
}
这里的区别是mapN { case _ => config }
。因为我已经有了一个配置文件,如果一切都有效,所以我不想从其成员那里重新创建配置文件。这是由于我通过config验证功能而不是其成员而引起的。
我工作场所的一个人告诉我这不是正确的方法,因为Cats Validated提供了一种在对象有效时构造对象的方法。如果对象的成员无效,则该对象不应存在或不可构造。这对我来说完全有意义。
那我应该做些改变吗?以上我正在接受吗?
PS:上面的Config只是一个示例,我的实际配置中可以包含其他case类作为其成员,而这些case类本身可以依赖于其他case类。
答案 0 :(得分:17)
像Cats这样的库提倡的那种编程的主要目标之一是使无效状态无法表示。根据这种理念,在理想情况下,不可能使用无效的成员数据创建Config
的实例(通过使用类似Refined的库,可以在其中表达复杂的约束,由类型系统跟踪,或仅通过隐藏不安全的构造函数进行跟踪)。在稍微不太完美的世界中,仍然有可能构造Config
的无效实例,但建议不要这样做,例如通过使用安全的构造函数(例如validatePerson
的{{1}}方法)。
这听起来像是您处在一个更加不完美的世界中,其中有Person
实例可能包含或可能不包含无效数据,并且您想验证它们以获取{{1 }},您知道这是有效的。这是完全有可能的,并且在某些情况下是合理的,并且如果您陷在这个不完美的世界中,则Config
方法是解决此问题的一种完全合法的方法。
但是,不利之处在于,编译器无法跟踪已经验证的Config
实例和尚未验证的实例之间的差异。您的程序中将有validateConfig
个实例,如果您想知道它们是否已经通过验证,则必须跟踪它们可能来自的所有位置。在某些情况下,这可能还不错,但是对于大型或复杂程序而言,这并不理想。
总结:理想情况下,每创建一个Config
实例时,您都将对其进行验证(甚至可能无法创建无效的实例),这样您就不必记住是否有给定的{{1} }是好还是不好-类型系统可以为您记住。如果不可能,例如您无法控制的API或定义,或者对于一个简单的用例而言,如果它似乎太繁琐,那么您使用Config
所做的事情是完全合理的。
作为脚注,由于您在上面已经说过,您有兴趣在Refined上进行详细介绍,因此在这种情况下,它为您提供了避免出现Config
形状的更多功能的方法。例如,现在您的Config
方法可能需要一个validateConfig
并返回一个A => ValidationResult[A]
。您可以对此签名进行与我上面针对validateName
相同的参数-一旦使用结果(通过将函数映射到String
或其他方式),您只有一个字符串,并且类型不会告诉您它已经被验证。
Refined允许您执行的操作是编写这样的方法:
ValidationResult[String]
…其中Config => ValidationResult[Config]
可能指定最小长度,或者字符串匹配特定的正则表达式,等等。重要的是,您不是在验证Validated
并返回{ {1}},只有您知道一些有关信息,您正在验证def validateName(in: String): ValidationResult[Refined[String, SomeProperty]] = ...
并返回编译器知道的SomeProperty
信息(通过String
包装器。
同样,对于您的用例来说,这可能是(好吧,可能是)过大的杀伤力,您可能会发现,可以在程序中进一步推动这一原理(对类型进行跟踪验证),您会发现这很高兴。