Обрезать значения полей String класса case - PullRequest
0 голосов
/ 08 февраля 2019

Я пишу обобщенную функцию, используя shapeless , которая принимает экземпляр case class и обрезает все значения полей, которые являются строковыми.Класс case может иметь дополнительные поля, вложенные объекты, списки и т. Д.

У меня есть класс case 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())))

Как я могу решить эту проблему?

1 Ответ

0 голосов
/ 08 февраля 2019

Во-первых, похоже, что он работает на address, а также name в вашем закомментированном выводе, что и следовало ожидать.Он не работает на friends, потому что List[Person] соответствует случаю skipCase - это ни Option[String], ни List[String].

Самый простой способ исправить это - использовать комбинатор everywhere Shapeless,Учитывая приведенный выше код, вы можете написать следующее:

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] case или более общий регистр, который будет соответствовать типам, подобным этому, и применять trimmer рекурсивно.Так как вы говорите, что хотите обрезать все строки, тем не менее, everywhere звучит так, как будто вы хотите.

...