代码之家  ›  专栏  ›  技术社区  ›  vicaba

不成形。引用1个构造函数参数的所有case类

  •  1
  • vicaba  · 技术社区  · 8 年前

    我试图泛化1参数构造函数的所有case类,使用shapeless为它们创建Json序列化程序。

    到目前为止,我所做的是:

    object ShapelessJsonOFormat extends ProductTypeClassCompanion[OFormat] {
      object typeClass extends ProductTypeClass[OFormat] {
        override def product[H, T <: HList](ch: OFormat[H], ct: OFormat[T]): OFormat[H :: T] = new OFormat[H :: T] {
          override def reads(json: JsValue): JsResult[H :: T] =
            for {
              h <- ch.reads(json)
              t <- ct.reads(json)
            } yield h :: t
    
    
          override def writes(o: H :: T): JsObject = ch.writes(o.head) ++ ct.writes(o.tail)
        }
    
        override def emptyProduct: OFormat[HNil] = new OFormat[HNil] {
    
          override def reads(json: JsValue): JsResult[HNil] = JsSuccess(HNil)
    
          override def writes(o: HNil): JsObject = JsObject.empty
        }
    
        override def project[F, G](
          instance: => OFormat[G],
          to: (F) => G,
          from: (G) => F): OFormat[F] = new OFormat [F] {
          override def writes(o: F): JsObject = instance.writes(to(o))
    
          override def reads(json: JsValue): JsResult[F] = instance.reads(json).map(from)
        }
      }
    }
    

    我没有试过,但这不是我真正想要的。问题是,扩展ProductTypeClassCompanion意味着对所有HList进行泛化,以便能够“添加”我在这里被迫使用JSonObject的两个JSON(参见 ++ override def writes(o: H :: T): JsObject = ch.writes(o.head) ++ ct.writes(o.tail) ). 我真正需要的是概括所有类型的列表 T :: HNil Product1[T]

    1 回复  |  直到 8 年前
        1
  •  3
  •   HTNW    8 年前

    如果要将其限制为仅处理单参数案例类,则不能使用 ProductTypeClass . 其目的是归纳概括为 任意算术乘积。你想坚持算术1,所以你有冲突。你只要不用(小)样板自己写就行了 ProductTypeclass

    object ShapelessJsonOFormat {
      implicit def caseHListArity1[Head](implicit
        headFmt: Lazy[OFormat[Head]] // Use Lazy in some places to get around the (incorrect) implicit divergence check in the compiler
      ): OFormat[Head :: HNil] = new OFormat[Head :: HNil] {
        // ... serialize a Head :: HNil given headFmt.value: OFormat[Head]
      }
    
      implicit def caseGeneric[I, O](implicit
        gen: Generic.Aux[I, O],
        oFmt: Lazy[OFormat[O]]
      ): OFormat[I] = new OFormat[I] {
        // ... serialize an I given a Generic I => O and oFmt.value: OFormat[O]
      }
    }
    

    JSONObject 在arity抽象版本中。这是因为你正在使用 Generic LabelledGeneric ,因此您没有能力为产品的元素提供字段名,因此它们在一个级别上混在一起。您可以正常使用 LabelledProductTypeClass 但事实并非如此 相当地

    type OFormatObject[A] = OFormat[A] { def write(value: A): JsObject }
    object ShapelessJsonOFormat {
      implicit val caseHNil: OFormatObject[HNil] = new OFormat[HNil] {
        override def read(json: JsValue) = HNil
        override def write(value: HNil) = JsObject.empty
      }
    
      implicit def caseHCons[
        HeadName <: Symbol,
        Head,
        Tail <: HList
      ](implicit
        headFmt: Lazy[OFormat[Head]],
        nameWitness: Witness.Aux[HeadName],
        tailFmt: Lazy[OFormatObject[Tail]]
      ): OFormatObject[FieldType[HeadName, Head] :: Tail]
      = new OFormat[FieldType[HeadName, Head] :: Tail] {
        private val fieldName = nameWitness.value.name // Witness[_ <: Symbol] => Symbol => String
        override def read(json: JsValue): FieldType[HeadName, Head] :: Tail = {
          val headObj = json.asJsObject.get(fieldName)
          val head = headFmt.read(headObj)
          val tail = tailFmt.read(json)
          field[HeadName](head) :: tail
        }
        override def write(value: FieldType[HeadName, Head] :: Tail): JsObject = {
          val tail = tailFmt.write(value.tail)
          val head = headFmt.write(value.head)
          tail + JsObject(fieldName -> head) // or similar
        }
      }
    
      implicit def caseLabelledGeneric[I, O](implicit
        gen: LabelledGeneric.Aux[I, O],
        oFmt: Lazy[OFormatObject[O]]
      ): OFormatObject[I] = new OFormat[I] {
        override def read(json: JsValue): I = gen.from(oFmt.value.read(json))
        override def write(value: I): JsObject = oFmt.value.write(gen.to(value))
      }
    }
    

    OFormatObject 谈论 OFormat s保证 write JsObject OFormatObject[HNil] 那只是 { read = _ => HNil; write = _ => {} } . 如果有一个序列化程序 Head ( OFormat[Head] Tail ( OFormatObject[Tail] ),我们有一些单例类型,它表示 HeadName <: Symbol ,在中实现 Witness.Aux[HeadName] ),然后 caseHCons OFormatObject[FieldName[HeadName, Head] :: Tail] ,看起来像 { read = { headName: head, ..tail } => head :: tail; write = head :: tail => { headName: head, ..tail } . 然后我们使用 caseLabelledGeneric HList FieldType 分为一般案例类。