Scala:有一种通用的方法来修剪案例类的所有String字段吗?

时间:2017-08-25 16:39:48

标签: scala trim case-class

我需要一种通用方法(例如某些函数),它接受case类(任何类型)的实例,并返回此实例的副本,但带有修剪后的字符串。

(最好没有反思)

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您可以使用shapeless执行此操作:

import shapeless._
import shapeless.ops.hlist._

// Trims if passed a String value, otherwise returns the value unchanged
object Trimmer extends Poly1 {
  implicit val stringTrim = at[String] { _.trim }
  implicit def noop[T]    = at[T] { identity }
}

// Uses a Generic to transform the instance into an HList, maps over it 
// and convert it back into the case class
def trimCaseClass[C, H <: HList](c: C)
    (implicit g: Generic.Aux[C, H], m: Mapper.Aux[Trimmer.type, H, H]): C = {
  val hlist = g.to(c)
  val trimmed = hlist.map(Trimmer)
  g.from(trimmed)
}

然后:

scala> case class A(s1: String, s2: String, i: Int)
defined class A

scala> val a = A("   1   ", "2", 3)
a: A = A(   1   ,2,3)

scala> trimCaseClass(a)
res0: A = A(1,2,3)

答案 1 :(得分:2)

使用shapeless

import shapeless._, ops.hlist._

object trimString extends Poly1 {
  implicit val stringCase = at[String](_.trim)
  implicit def restCase[A] = at[A](a => a)
}

def trimAllIn[A, R <: HList](a: A)(implicit
    gen: Generic.Aux[A, R],
  mapper: Mapper.Aux[trimString.type, R, R]
) = gen.from(mapper(gen.to(a)))

case class Foo(string: String, int: Int)
case class Bar(string1: String, string2: String)

assert { trimAllIn(Foo("  trim me ", 42)) == Foo("trim me", 42) }
assert { trimAllIn(Bar("  trim me", "and me too   ")) == Bar("trim me", "and me too") }

Runnable version here