Scala:反射和案例类
发布时间:2020-12-16 19:20:11 所属栏目:安全 来源:网络整理
导读:以下代码成功,但有更好的方法做同样的事情吗?案例类可能是特定的东西吗?在下面的代码中,对于我的简单案例类中String类型的每个字段,代码遍历我的案例类的实例列表,并查找该字段的最长字符串的长度. case class CrmContractorRow( id: Long,bankCharges: St
以下代码成功,但有更好的方法做同样的事情吗?案例类可能是特定的东西吗?在下面的代码中,对于我的简单案例类中String类型的每个字段,代码遍历我的案例类的实例列表,并查找该字段的最长字符串的长度.
case class CrmContractorRow( id: Long,bankCharges: String,overTime: String,name$id: Long,mgmtFee: String,contractDetails$id: Long,email: String,copyOfVisa: String) object Go { def main(args: Array[String]) { val a = CrmContractorRow(1,"1",4444,1,"1") val b = CrmContractorRow(22,"22",22,"55555","nine long","22") val c = CrmContractorRow(333,"333",333,"333") val rows = List(a,b,c) c.getClass.getDeclaredFields.filter(p => p.getType == classOf[String]).foreach{f => f.setAccessible(true) println(f.getName + ": " + rows.map(row => f.get(row).asInstanceOf[String]).maxBy(_.length)) } } } 结果: bankCharges: 3 overTime: 3 mgmtFee: 5 email: 9 copyOfVisa: 3 解决方法
如果你想用Shapeless做这种事情,我强烈建议定义一个处理复杂部分的自定义类型,并允许你将这些东西与其余的逻辑分开.
在这种情况下,它听起来像你特别想要做的棘手部分是从一个案例类的所有String成员的字段名称到字符串长度的映射.这是一个类型类,它执行此操作: import shapeless._,shapeless.labelled.FieldType trait StringFieldLengths[A] { def apply(a: A): Map[String,Int] } object StringFieldLengths extends LowPriorityStringFieldLengths { implicit val hnilInstance: StringFieldLengths[HNil] = new StringFieldLengths[HNil] { def apply(a: HNil): Map[String,Int] = Map.empty } implicit def caseClassInstance[A,R <: HList](implicit gen: LabelledGeneric.Aux[A,R],sfl: StringFieldLengths[R] ): StringFieldLengths[A] = new StringFieldLengths[A] { def apply(a: A): Map[String,Int] = sfl(gen.to(a)) } implicit def hconsStringInstance[K <: Symbol,T <: HList](implicit sfl: StringFieldLengths[T],key: Witness.Aux[K] ): StringFieldLengths[FieldType[K,String] :: T] = new StringFieldLengths[FieldType[K,String] :: T] { def apply(a: FieldType[K,String] :: T): Map[String,Int] = sfl(a.tail).updated(key.value.name,a.head.length) } } sealed class LowPriorityStringFieldLengths { implicit def hconsInstance[K,V,T <: HList](implicit sfl: StringFieldLengths[T] ): StringFieldLengths[FieldType[K,V] :: T] = new StringFieldLengths[FieldType[K,V] :: T] { def apply(a: FieldType[K,V] :: T): Map[String,Int] = sfl(a.tail) } } 这看起来很复杂,但是一旦你开始使用Shapeless,你就会学会在睡梦中写下这种东西. 现在,您可以以相对简单的方式编写操作的逻辑: def maxStringLengths[A: StringFieldLengths](as: List[A]): Map[String,Int] = as.map(implicitly[StringFieldLengths[A]].apply).foldLeft( Map.empty[String,Int] ) { case (x,y) => x.foldLeft(y) { case (acc,(k,v)) => acc.updated(k,acc.get(k).fold(v)(accV => math.max(accV,v))) } } 然后(给出问题中定义的行): scala> maxStringLengths(rows).foreach(println) (bankCharges,3) (overTime,3) (mgmtFee,5) (email,9) (copyOfVisa,3) 这适用于绝对任何案例类. 如果这是一次性的事情,你也可以使用运行时反射,或者你可以在Giovanni Caporaletti的答案中使用Poly1方法 – 它不那么通用,它以我不喜欢的方式混合了解决方案的不同部分,但它应该工作得很好.如果这是你做了很多事情的话,我会建议我在这里给出的方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |