我写使用shapeless,需要一个case class
的实例,并修剪是字符串字段的所有值的通用函数。此案类可以有可选字段,嵌套的对象,列表等。
我有一个案例类Person
。
case class Person(name: Option[String], address: List[String], friends: List[Person])
我目前拥有的功能:
import shapeless._, ops.hlist._
object trimmer extends Poly1 {
implicit val stringOptCase = at[Option[String]](_.map(_.trim))
implicit val stringListCase = at[List[String]](_.map(_.trim))
implicit def skipCase[A] = at[A](identity)
}
def trimStringValues[A, R <: HList](a: A)(implicit
gen: Generic.Aux[A, R],
mapper: Mapper.Aux[trimmer.type, R, R]
) = gen.from(mapper(gen.to(a)))
当我使用上述功能,它仅适用于类name
的根级别Person
场。它不会对列表或对象领域的工作。
val person = Person(name = Some(" john "), address = List(" ny"," vegas "), friends = List(Person(Some(" alicia"), List(" peter"), Nil)))
trimStringValues(person) // Person(Some(john),List(ny, vegas),List(Person(Some( alicia),List( peter),List())))
我该如何解决这个问题?
首先,它似乎是工作在address
以及name
在你的评论输出,这是可以预料的。它不是friends
工作,因为List[Person]
匹配skipCase
情况下,它是既非Option[String]
或List[String]
。
解决这个问题的最简单的方法是用无形的everywhere
组合子。鉴于上面的代码,你可以写:
scala> shapeless.everywhere(trimmer)(person)
res1: Person = Person(Some(john),List(ny, vegas),List(Person(Some(alicia),List(peter),List())))
事实上,你可以完成同样的事情用一个更简单的trimmer
实现:
object trimStrings extends Poly1 {
implicit val stringCase: Case.Aux[String, String] = at[String](_.trim)
}
或等价但更简洁:
import shapeless.poly.->
object trimStrings extends (String -> String)(_.trim)
接着:
scala> shapeless.everywhere(trimStrings)(person)
res5: Person = Person(Some(john),List(ny, vegas),List(Person(Some(alicia),List(peter),List())))
如果你想到底是哪串被修剪过更多的控制,你可以回到你原来的实现,要么添加一个明确的List[Person]
情况下,或将匹配类型,如本和递归应用trimmer
一个更通用的情况。既然你说你要修剪的所有字符串,虽然everywhere
听起来就像是你想要的。