gpt4 book ai didi

Scala:从嵌套案例类到展平案例类

转载 作者:行者123 更新时间:2023-12-01 03:10:45 25 4
gpt4 key购买 nike

问题是:

如何构建一个通用函数,该函数可以采用由其他案例类组成的任何案例类,并将其展平为一个案例类,其中包含组合案例类中每个案例类的所有值?

例如,我想转换一个 嵌套案例类 像这样:

case class A(first: String, second: String)
case class B(value: String)

case class Nested(a: A, b: B)

扁平案例类 像这样:
case class Flatten(aFirst: String, aSecond: String, bValue: String)

但我想 避免构建我自己的构造函数 (或手动创建一个函数)像这样:
object Flatten {

def apply(nested: Nested): Flatten = {
Flatten(nested.a.first, nested.a.second, nested.b.value)
}
}

注意:在实际用例中,案例类更复杂,我想在不同的案例类上多次使用该方法。

最佳答案

假设目标案例类字段名称具有预定义格式,您可以使用反射 api。看一下例子

import scala.reflect.runtime.universe._

class Converter(any: Any) {
private val rm = runtimeMirror(any.getClass.getClassLoader)

private def nameToPath(name: String, pathElem: String = "", pathElems: List[String] = List()): List[String] =
if (name.isEmpty) pathElems :+ pathElem.toLowerCase()
else if (name.head.isUpper) nameToPath(name.tail, name.head.toString, pathElems :+ pathElem)
else nameToPath(name.tail, pathElem + name.head, pathElems)

private def valueByPath(v: Any, pathElems: List[String]): Any =
if (pathElems.isEmpty) v
else {
val im = rm.reflect(v)
val fieldName = TermName(pathElems.head)
val field = im.symbol.info.member(fieldName).asTerm
val value = im.reflectField(field).get
valueByPath(value, pathElems.tail)
}

def convertTo[T: TypeTag]: T = {
val target = typeOf[T]
val fieldNames = target.decls.sorted.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}

val paths = fieldNames.map(s => nameToPath(s.name.toString))
val values = paths.map(valueByPath(any, _))

val constructorSymbol = target.decl(termNames.CONSTRUCTOR)

val defaultConstructor = constructorSymbol match {
case cs: MethodSymbol => cs
case ts: TermSymbol =>
ts.alternatives.collectFirst {
case ms: MethodSymbol if ms.isPrimaryConstructor => ms
}.get
}

val cs = target.typeSymbol.asClass
val cm = rm.reflectClass(cs)
val constructor = cm.reflectConstructor(defaultConstructor)
constructor(values: _*).asInstanceOf[T]
}
}

implicit class AnyOps(any: Any) {
def to[T: TypeTag]: T = new Converter(any).convertTo[T]
}

使用
val a = A("1", "2")
val b = B("3")
val n = Nested(a, b)

val r = n.to[Flatten]

输出
r: Flatten = Flatten(1,2,3)

关于Scala:从嵌套案例类到展平案例类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52514072/

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