gpt4 book ai didi

Scala:反射和案例类

转载 作者:行者123 更新时间:2023-12-04 05:29:35 24 4
gpt4 key购买 nike

下面的代码成功了,但是有没有更好的方法来做同样的事情?也许某些特定于案例类的东西?在下面的代码中,对于我的简单 case 类中的每个 String 类型的字段,代码遍历我的 case 类的实例列表并找到该字段的最长字符串的长度。

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","1",4444,"1",1,"1","1")
val b = CrmContractorRow(22,"22","22",22,"55555",22,"nine long","22")
val c = CrmContractorRow(333,"333","333",333,"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)))
}
}

然后(给定 rows,如问题中所定义):
scala> maxStringLengths(rows).foreach(println)
(bankCharges,3)
(overTime,3)
(mgmtFee,5)
(email,9)
(copyOfVisa,3)

这绝对适用于任何案例类。

如果这是一次性的事情,您不妨使用运行时反射,或者您可以使用 Poly1 Giovanni Caporaletti 的答案中的方法 - 它不太通用,它以我不喜欢的方式混合了解决方案的不同部分,但它应该可以正常工作。不过,如果这是你经常做的事情,我会建议我在这里给出的方法。

关于Scala:反射和案例类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36452008/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com