使用 Shapeless 递归列出空字段
List null fields recursively with Shapeless
我正在尝试使用 Shapeless 递归地列出空字段。但它似乎并没有显示所有字段:
https://scastie.scala-lang.org/PtLdSRC2Qfipu054Hzerrw
import shapeless._
import shapeless.labelled.FieldType
trait NullFields[T] {
def apply(value: T, parent: String): Seq[String]
}
object NullFields extends NullFieldsLowPriority {
implicit lazy val hNil = new NullFields[HNil] {
override def apply(value: HNil, parent: String) = Seq.empty
}
implicit def hConsOption[K <: Symbol, V, TailFields <: HList](implicit
witness: Witness.Aux[K],
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, Option[V]] :: TailFields] {
override def apply(
params: FieldType[K, Option[V]] :: TailFields,
parent: String
) =
(if (params.head.isEmpty) Seq(parent + witness.value.name)
else Seq.empty) ++
tailNullFields(params.tail, parent)
}
implicit def hConsCaseClass[
K <: Symbol,
CC <: Product,
Fields <: HList,
TailFields <: HList
](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields],
witness: Witness.Aux[K],
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, CC] :: TailFields] {
override def apply(params: FieldType[K, CC] :: TailFields, parent: String) =
nullFields(generic.to(params.head), s"$parent${witness.value.name}.") ++
tailNullFields(params.tail, parent)
}
implicit def caseClass[CC, Fields <: HList](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields]
) = new NullFields[CC] {
override def apply(value: CC, parent: String) =
nullFields(generic.to(value), parent)
}
}
trait NullFieldsLowPriority {
implicit def hConsDefault[K <: Symbol, V, TailFields <: HList](implicit
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, V] :: TailFields] {
override def apply(params: FieldType[K, V] :: TailFields, parent: String) =
tailNullFields(params.tail, parent)
}
}
case class B(
balba: Int = 0,
profile_experience_desc: Option[String] = None,
vmaf: Va
)
case class Va(
tw_segment: Option[Double],
i20_segment: Option[Double],
ttq_segment: Option[Int]
)
println(implicitly[NullFields[B]].apply(B(vmaf = Va(None, None, None)), ""))
我不确定这是否正是您想要的,但我希望您可以对其进行调整以使其满足您的需要。我将以下内容视为 null
s:
- 全部
None
null
的任何其他类型
- 递归
null
s 或 None
s 在 类 and/or Option
s 的情况下找到
您可以添加更多的隐式来处理其他情况:
import shapeless._
import shapeless.labelled.FieldType
trait NullFields[T] {
def apply(value: T, parent: String): Seq[String]
}
object NullFields extends LowPrioriyImplicits {
def apply[A](implicit nullFields: NullFields[A]): NullFields[A] = nullFields
implicit class NullFieldsOps[A](a: A) {
def nulls(implicit ev: NullFields[A]) = NullFields[A].apply(a, "")
}
implicit def option[V](implicit nullFields: NullFields[V]): NullFields[Option[V]] =
(option: Option[V], parent: String) =>
if (option.isEmpty) Seq(parent)
else nullFields(option.head, parent)
implicit def caseClass[CC, Fields <: HList](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields]
): NullFields[CC] = (value: CC, parent: String) => nullFields(generic.to(value), parent)
implicit def hCons[K <: Symbol, Field, TailFields <: HList](implicit
witness: Witness.Aux[K],
nullFields: Lazy[NullFields[Field]],
tailNullFields: Lazy[NullFields[TailFields]]
): NullFields[FieldType[K, Field] :: TailFields] =
(params: FieldType[K, Field] :: TailFields, parent: String) =>
nullFields.value(params.head, (if (parent.isEmpty) "" else s"$parent.") + witness.value.name) ++
tailNullFields.value(params.tail, parent)
implicit val hNil: NullFields[HNil] = (value: HNil, parent: String) => Seq.empty
}
trait LowPrioriyImplicits {
implicit def other[A]: NullFields[A] =
(value: A, parent: String) => if (value == null) Seq(parent) else Seq.empty
}
Scastie link 同样
我正在尝试使用 Shapeless 递归地列出空字段。但它似乎并没有显示所有字段:
https://scastie.scala-lang.org/PtLdSRC2Qfipu054Hzerrw
import shapeless._
import shapeless.labelled.FieldType
trait NullFields[T] {
def apply(value: T, parent: String): Seq[String]
}
object NullFields extends NullFieldsLowPriority {
implicit lazy val hNil = new NullFields[HNil] {
override def apply(value: HNil, parent: String) = Seq.empty
}
implicit def hConsOption[K <: Symbol, V, TailFields <: HList](implicit
witness: Witness.Aux[K],
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, Option[V]] :: TailFields] {
override def apply(
params: FieldType[K, Option[V]] :: TailFields,
parent: String
) =
(if (params.head.isEmpty) Seq(parent + witness.value.name)
else Seq.empty) ++
tailNullFields(params.tail, parent)
}
implicit def hConsCaseClass[
K <: Symbol,
CC <: Product,
Fields <: HList,
TailFields <: HList
](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields],
witness: Witness.Aux[K],
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, CC] :: TailFields] {
override def apply(params: FieldType[K, CC] :: TailFields, parent: String) =
nullFields(generic.to(params.head), s"$parent${witness.value.name}.") ++
tailNullFields(params.tail, parent)
}
implicit def caseClass[CC, Fields <: HList](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields]
) = new NullFields[CC] {
override def apply(value: CC, parent: String) =
nullFields(generic.to(value), parent)
}
}
trait NullFieldsLowPriority {
implicit def hConsDefault[K <: Symbol, V, TailFields <: HList](implicit
tailNullFields: NullFields[TailFields]
) = new NullFields[FieldType[K, V] :: TailFields] {
override def apply(params: FieldType[K, V] :: TailFields, parent: String) =
tailNullFields(params.tail, parent)
}
}
case class B(
balba: Int = 0,
profile_experience_desc: Option[String] = None,
vmaf: Va
)
case class Va(
tw_segment: Option[Double],
i20_segment: Option[Double],
ttq_segment: Option[Int]
)
println(implicitly[NullFields[B]].apply(B(vmaf = Va(None, None, None)), ""))
我不确定这是否正是您想要的,但我希望您可以对其进行调整以使其满足您的需要。我将以下内容视为 null
s:
- 全部
None
null
的任何其他类型
- 递归
null
s 或None
s 在 类 and/orOption
s 的情况下找到
您可以添加更多的隐式来处理其他情况:
import shapeless._
import shapeless.labelled.FieldType
trait NullFields[T] {
def apply(value: T, parent: String): Seq[String]
}
object NullFields extends LowPrioriyImplicits {
def apply[A](implicit nullFields: NullFields[A]): NullFields[A] = nullFields
implicit class NullFieldsOps[A](a: A) {
def nulls(implicit ev: NullFields[A]) = NullFields[A].apply(a, "")
}
implicit def option[V](implicit nullFields: NullFields[V]): NullFields[Option[V]] =
(option: Option[V], parent: String) =>
if (option.isEmpty) Seq(parent)
else nullFields(option.head, parent)
implicit def caseClass[CC, Fields <: HList](implicit
generic: LabelledGeneric.Aux[CC, Fields],
nullFields: NullFields[Fields]
): NullFields[CC] = (value: CC, parent: String) => nullFields(generic.to(value), parent)
implicit def hCons[K <: Symbol, Field, TailFields <: HList](implicit
witness: Witness.Aux[K],
nullFields: Lazy[NullFields[Field]],
tailNullFields: Lazy[NullFields[TailFields]]
): NullFields[FieldType[K, Field] :: TailFields] =
(params: FieldType[K, Field] :: TailFields, parent: String) =>
nullFields.value(params.head, (if (parent.isEmpty) "" else s"$parent.") + witness.value.name) ++
tailNullFields.value(params.tail, parent)
implicit val hNil: NullFields[HNil] = (value: HNil, parent: String) => Seq.empty
}
trait LowPrioriyImplicits {
implicit def other[A]: NullFields[A] =
(value: A, parent: String) => if (value == null) Seq(parent) else Seq.empty
}
Scastie link 同样