Cats Validated表单验证:如何避免冗余参数重映射?
解决表单验证中
mapN冗余字段映射的问题 嘿,这个场景我太熟悉了——在用Cats的Validated做表单验证时,当你只需要验证case class的部分字段,还要手动把所有字段(包括不需要验证的)塞进mapN的构造函数里,确实有点啰嗦!好消息是,你的需求完全可行,而且有很简洁的解决办法。
核心思路:利用Case Class的copy方法
Scala的case class自带copy方法,它允许你只修改需要更新的字段,其余字段自动复用原实例的值。这正好能解决你不想重复写冗余字段的问题。
举个具体的例子:假设你有这样的Cat类和验证逻辑:
import cats.data.Validated import cats.data.NonEmptyList case class Cat(name: String, age: Int, weight: Double) // 原Cat实例 val cat = Cat("Mittens", 3, 3.5) // 针对name和age的验证逻辑 def validateName(name: String): Validated[NonEmptyList[String], String] = if (name.length >= 2) Validated.valid(name) else Validated.invalid(NonEmptyList.one("Name must be at least 2 characters")) def validateAge(age: Int): Validated[NonEmptyList[String], Int] = if (age > 0) Validated.valid(age) else Validated.invalid(NonEmptyList.one("Age must be positive")) val validatedName = validateName(cat.name) val validatedAge = validateAge(cat.age)
原来的写法是:
val validatedCat = (validatedName, validatedAge).mapN((n, a) => Cat(n, a, cat.weight))
用copy方法简化后:
val validatedCat = (validatedName, validatedAge).mapN(cat.copy(name = _, age = _))
这样你只需要传入验证后的字段,weight字段会自动复用原cat实例的值,完全避免了冗余的字段重写。
更复杂场景的扩展
如果你的Cat类有更多字段,或者需要验证嵌套字段,这个方法依然适用。比如Cat有color和breed字段:
case class Cat(name: String, age: Int, weight: Double, color: String, breed: String) val cat = Cat("Whiskers", 5, 4.2, "orange", "tabby") // 只验证name和age val validatedCat = (validatedName, validatedAge).mapN(cat.copy(name = _, age = _))
不管有多少个不需要验证的字段,copy都会帮你自动复用,代码依然简洁。
为什么这可行?
mapN的本质是把多个Applicative类型(这里是Validated)的结果组合起来,然后传递给一个函数。而cat.copy(name = _, age = _)正好是一个接受String和Int参数、返回Cat实例的函数——完全符合mapN的要求。
内容的提问来源于stack exchange,提问作者fedorshishi
相关产品推荐
相关产品推荐

