scala 正在获取指向另一个案例类的案例类定义

vwkv1x7d  于 2023-02-08  发布在  Scala
关注(0)|答案(1)|浏览(178)

我正在寻找获得案例类定义。
从SO中,我按照Get field names list from case class收集了这个实践,答案是Dia Kharrat使用反射。
一些实验中,我有一个案例类引用另一个案例类,嵌套。我们可以得到元数据很容易地扩展在某种方式?

import scala.collection.mutable.ArrayBuffer

case class MyChgClass(b: Option[String], c: Option[String], d: Option[String])
case class MyFullClass(k: Int, b: String, c: String, d: String)
case class MyEndClass(id: Int, after: MyFullClass)

def classAccessors[T: TypeTag]: List[MethodSymbol] = typeOf[T].members.collect {
 case m: MethodSymbol if m.isCaseAccessor => m
}.toList

val z1 = classAccessors[MyChgClass]
val z2 = classAccessors[MyFullClass]
val z3 = classAccessors[MyEndClass]

退货:

z1: List[reflect.runtime.universe.MethodSymbol] = List(value d, value c, value b)
z2: List[reflect.runtime.universe.MethodSymbol] = List(value d, value c, value b, value k)
z3: List[reflect.runtime.universe.MethodSymbol] = List(value after, value id)

因此:
1.正在查找扩展事例类MyEndClass。
1.选项方面似乎未提供。可能吗?

1cklez4t

1cklez4t1#

1.选项方面似乎未提供。可能吗?
您是否正在寻找.name.typeSignature

val z1 = classAccessors[MyChgClass]
val z2 = classAccessors[MyFullClass]
val z3 = classAccessors[MyEndClass]

z1.map(_.name) // List(d, c, b)
z1.map(_.typeSignature) // List(Option[String], Option[String], Option[String])
z2.map(_.name) // List(d, c, b, k)
z2.map(_.typeSignature) // List(String, String, String, Int)
z3.map(_.name) // List(after, id)
z3.map(_.typeSignature) // List(MyFullClass, Int)

如果您的类在编译时已知,则使用编译时反射(即macros而不是runtime reflection)是有意义的
x一个一个一个一个x一个一个二个x
更好的方法是使用一个将这些宏封装到类型类中的库,在Shapeless中,访问case-class字段的名称和类型的类型类是LabelledGeneric
一个三个三个一个
1.希望扩展案例类MyEndClass
您可以尝试类型类LabelledGenericMapper等的深度版本。

import shapeless.labelled.{FieldType, field}
import shapeless.{::, DepFn0, DepFn1, HList, HNil, LabelledGeneric, Poly0, Poly1, Typeable, Witness, poly}

trait DeepLabelledGeneric[T <: Product] {
  type Repr <: HList
  def to(t: T): Repr
  def from(r: Repr): T
}

object DeepLabelledGeneric {
  type Aux[T <: Product, Repr0 <: HList] = DeepLabelledGeneric[T] {type Repr = Repr0}
  def instance[T <: Product, Repr0 <: HList](f: T => Repr0, g: Repr0 => T): Aux[T, Repr0] = new DeepLabelledGeneric[T] {
    override type Repr = Repr0
    override def to(t: T): Repr = f(t)
    override def from(r: Repr): T = g(r)
  }

  implicit def deepGeneric[A <: Product, L <: HList, L1 <: HList](implicit
    labelledGeneric: LabelledGeneric.Aux[A, L],
    hListDeepLabelledGeneric: HListDeepLabelledGeneric.Aux[L, L1]
  ): Aux[A, L1] = instance(a => hListDeepLabelledGeneric.to(labelledGeneric.to(a)), l1 => labelledGeneric.from(hListDeepLabelledGeneric.from(l1)))
}

trait HListDeepLabelledGeneric[T <: HList] {
  type Repr <: HList
  def to(t: T): Repr
  def from(r: Repr): T
}

trait LowPriorityHListDeepLabelledGeneric {
  type Aux[T <: HList, Repr0 <: HList] = HListDeepLabelledGeneric[T] {type Repr = Repr0}

  def instance[T <: HList, Repr0 <: HList](f: T => Repr0, g: Repr0 => T): Aux[T, Repr0] = new HListDeepLabelledGeneric[T] {
    override type Repr = Repr0
    override def to(t: T): Repr = f(t)
    override def from(r: Repr): T = g(r)
  }

  implicit def headNotCaseClass[H, T <: HList, T_hListDeepLGen <: HList](implicit
    tailHListDeepLabelledGeneric: HListDeepLabelledGeneric.Aux[T, T_hListDeepLGen]
  ): Aux[H :: T, H :: T_hListDeepLGen] = instance({
    case h :: t => h :: tailHListDeepLabelledGeneric.to(t)
  }, {
    case h :: t => h :: tailHListDeepLabelledGeneric.from(t)
  })
}

object HListDeepLabelledGeneric extends LowPriorityHListDeepLabelledGeneric {
  implicit val hNil: Aux[HNil, HNil] = instance(identity, identity)

  implicit def headCaseClass[K <: Symbol, H <: Product, T <: HList, H_deepLGen <: HList, T_hListDeepLGen <: HList](implicit
    headDeepLabelledGeneric: DeepLabelledGeneric.Aux[H, H_deepLGen],
    tailHListDeepLabelledGeneric: HListDeepLabelledGeneric.Aux[T, T_hListDeepLGen]
  ): Aux[FieldType[K, H] :: T, FieldType[K, H_deepLGen] :: T_hListDeepLGen] = instance({
    case h :: t => field[K](headDeepLabelledGeneric.to(h)) :: tailHListDeepLabelledGeneric.to(t)
  }, {
    case h :: t => field[K](headDeepLabelledGeneric.from(h)) :: tailHListDeepLabelledGeneric.from(t)
  })
}

trait DeepMapper[P <: Poly1, In <: HList] extends DepFn1[In] {
  type Out <: HList
}

trait LowPriorityDeepMapper {
  def apply[P <: Poly1, L <: HList](implicit deepMapper: DeepMapper[P, L]): Aux[P, L, deepMapper.Out] = deepMapper
  type Aux[P <: Poly1, In <: HList, Out0 <: HList] = DeepMapper[P, In] {type Out = Out0}
  def instance[P <: Poly1, In <: HList, Out0 <: HList](f: In => Out0): Aux[P, In, Out0] = new DeepMapper[P, In] {
    override type Out = Out0
    override def apply(t: In): Out = f(t)
  }

  implicit def headNotHList[P <: Poly1, H, T <: HList](implicit
    headCase: poly.Case1[P, H],
    tailDeepMapper: DeepMapper[P, T]
  ): Aux[P, H :: T, headCase.Result :: tailDeepMapper.Out] =
    instance(l => headCase(l.head) :: tailDeepMapper(l.tail))
}

object DeepMapper extends LowPriorityDeepMapper {
  implicit def hNil[P <: Poly1]: Aux[P, HNil, HNil] = instance(_ => HNil)

  implicit def headHList[P <: Poly1, K <: Symbol, H <: HList, H_deepMap <: HList, T <: HList](implicit
    headDeepMapper: DeepMapper.Aux[P, H, H_deepMap],
    headCase: poly.Case1[P, FieldType[K, H_deepMap]],
    tailDeepMapper: DeepMapper[P, T]
  ): Aux[P, FieldType[K, H] :: T, headCase.Result :: tailDeepMapper.Out] =
    instance(l => headCase(field[K](headDeepMapper(l.head))) :: tailDeepMapper(l.tail))
}

trait DeepFillWith[P <: Poly0, L <: HList] extends DepFn0 {
  type Out = L
}

trait LowPriorityDeepFillWith {
  def apply[P <: Poly0, L <: HList](implicit deepFillWith: DeepFillWith[P, L]): DeepFillWith[P, L] = deepFillWith
  def instance[P <: Poly0, L <: HList](f: => L): DeepFillWith[P, L] = new DeepFillWith[P, L] {
    override def apply(): L = f
  }

  implicit def headNotHList[P <: Poly0, H, T <: HList](implicit
    headCase: poly.Case0.Aux[P, H],
    tailDeepFillWith: DeepFillWith[P, T]
  ): DeepFillWith[P, H :: T] =
    instance(headCase() :: tailDeepFillWith())
}

object DeepFillWith extends LowPriorityDeepFillWith {
  implicit def hNil[P <: Poly0]: DeepFillWith[P, HNil] = instance(HNil)

  implicit def headHList[P <: Poly1, K <: Symbol, H <: HList, T <: HList](implicit
    headDeepMapper: DeepMapper[P, H],
    tailDeepMapper: DeepMapper[P, T]
  ): Aux[P, FieldType[K, H] :: T, FieldType[K, headDeepMapper.Out] :: tailDeepMapper.Out] =
    instance(l => field[K](headDeepMapper(l.head)) :: tailDeepMapper(l.tail))
}

trait LowPriorityFieldNamesAndTypesPoly extends Poly1 {
  implicit def notHListCase[K <: Symbol, V](implicit
    witness: Witness.Aux[K],
    typeable: Typeable[V]
  ): Case.Aux[FieldType[K, V], (String, String)] =
    at(_ => (witness.value.name, typeable.describe))
}

object fieldNamesAndTypesPoly extends LowPriorityFieldNamesAndTypesPoly {
  implicit def hListCase[K <: Symbol, V <: HList](implicit
    witness: Witness.Aux[K],
  ): Case.Aux[FieldType[K, V], (String, V)] =
    at(v => (witness.value.name, v))
}

object nullPoly extends Poly0 {
  implicit def cse[A]: Case0[A] = at(null.asInstanceOf[A])
}

def classAccessors[T <: Product] = new PartiallyApplied[T]

class PartiallyApplied[T <: Product] {
  def apply[L <: HList]()(implicit
    deepLabelledGeneric: DeepLabelledGeneric.Aux[T, L],
    deepFillWith: DeepFillWith[nullPoly.type, L],
    deepMapper: DeepMapper[fieldNamesAndTypesPoly.type, L],
  ): deepMapper.Out = deepMapper(deepFillWith())
}
classAccessors[MyChgClass]() // (b,Option[String]) :: (c,Option[String]) :: (d,Option[String]) :: HNil
classAccessors[MyFullClass]() // (k,Int) :: (b,String) :: (c,String) :: (d,String) :: HNil
classAccessors[MyEndClass]() // (id,Int) :: (after,(k,Int) :: (b,String) :: (c,String) :: (d,String) :: HNil) :: HNil

Deriving nested shapeless lenses using only a type
Weird behavior trying to convert case classes to heterogeneous lists recursively with Shapeless
https://github.com/milessabin/shapeless/blob/main/examples/src/main/scala/shapeless/examples/deephlister.scala
Converting nested case classes to nested Maps using Shapeless
Automatically convert a case class to an extensible record in shapeless?

相关问题