Trim 个案例的字符串字段的值 class
Trim values of String fields of a case class
我正在使用 shapeless 编写一个通用函数,它采用 case class
的实例并修剪字符串字段的所有值。 case class 可以有可选字段、嵌套对象、列表等
我有一个案例classPerson
.
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)))
当我使用上面的函数时,它只对classPerson
的根级别name
字段有效。它不适用于列表或对象字段。
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]
。
解决此问题的最简单方法是使用 Shapeless 的 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())))
如果您想更好地控制 trimmed 的字符串,您可以 return 到您的原始实现并添加一个明确的 List[Person]
案例,或者一个更通用的案例这将匹配这样的类型并递归应用 trimmer
。既然你说你想要 trim all 字符串,那么 everywhere
听起来就是你想要的。
我正在使用 shapeless 编写一个通用函数,它采用 case class
的实例并修剪字符串字段的所有值。 case class 可以有可选字段、嵌套对象、列表等
我有一个案例classPerson
.
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)))
当我使用上面的函数时,它只对classPerson
的根级别name
字段有效。它不适用于列表或对象字段。
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]
。
解决此问题的最简单方法是使用 Shapeless 的 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())))
如果您想更好地控制 trimmed 的字符串,您可以 return 到您的原始实现并添加一个明确的 List[Person]
案例,或者一个更通用的案例这将匹配这样的类型并递归应用 trimmer
。既然你说你想要 trim all 字符串,那么 everywhere
听起来就是你想要的。