Рекурсивный список пустых полей с помощью 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)), ""))
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, что это именно то, что вы хотите, но я надеюсь, что вы сможете настроить его так, чтобы он работал в соответствии с вашими потребностями. Я рассматривал следующее как nulls:

  • Все None
  • Любые другие типы, которые null
  • Рекурсивные nulls или Nones найдены в классах case и/или Options

Вы можете добавить дополнительные имплициты для обработки других случаев:

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
}

Скасти ссылка для того же

Чёрт возьми! Большое спасибо! Я отредактировал, чтобы соответствовать именно тому, что я искал. Спасибо еще раз!

Joan 23.03.2022 17:16

@Джоан, Нп. Рад, что помогло. Я снова отредактировал его, чтобы придать классу знакомый вид. Вы можете проверить ссылку Scastie, которая предоставляет класс операций, который может удовлетворить ваши потребности.

Johny T Koshy 24.03.2022 00:42

Спасибо! Улучшил его еще больше, заменив instance на тип SAM и неявное преобразование на implicit class

Joan 24.03.2022 16:01

Другие вопросы по теме