복붙노트

[SCALA] 볼품를 사용하여 중첩 된지도에 중첩 된 경우 클래스를 변환

SCALA

볼품를 사용하여 중첩 된지도에 중첩 된 경우 클래스를 변환

나는 그것이지도 [문자열, 모든]에 중첩 된 경우 클래스를 변환하는 방법에 대한의 요약, 볼품를 사용하여이 문제를 해결하기 위해 노력하고, 여기에 예입니다 :

case class Person(name:String, address:Address)
case class Address(street:String, zip:Int)

val p = Person("Tom", Address("Jefferson st", 10000))

그것은 다음에 페이지를 변환하고 싶어 :

Map("name" -> "Tom", "address" -> Map("street" -> "Jefferson st", "zip" -> 10000))

나는 볼품 LabelledGeneric를 사용하여 일을하려고하고, 여기에 지금까지 무엇 I를 :

import shapeless._
import record._, syntax.singleton._
import ops.record._
import shapeless.ops.record._

def writer[T,A<:HList,H<:HList](t:T)
(implicit lGeneric:LabelledGeneric.Aux[T,A],
 kys:Keys.Aux[A,H],
 vls:Values[A]) = {
    val tGen = lGeneric.to(t)
    val keys = Keys[lGeneric.Repr].apply
    val values = Values[lGeneric.Repr].apply(tGen)
    println(keys)
    println(values)
  }

나는 각 값을 확인하고 값의 각 요소에 대한지도를 만들려고 노력하는 재귀 작가가 노력하고 있어요. 위의 코드는 잘 작동하지만 다음 코드를 사용하여 샘플 폴리와 값 반복을 할 때 나는이 오류를 얻었다.

values.map(identity)
//or
tGen.map(identity)

Error:(75, 19) could not find implicit value for parameter mapper: shapeless.ops.hlist.FlatMapper[shapeless.poly.identity.type,vls.Out]
    values.flatMap(identity)
                  ^
Error:(75, 19) not enough arguments for method flatMap: (implicit mapper: shapeless.ops.hlist.FlatMapper[shapeless.poly.identity.type,vls.Out])mapper.Out.
Unspecified value parameter mapper.
    values.flatMap(identity)
                  ^

나는 그 오류를 받고 있어요 이유를 모르겠어요. 또한 볼품를 사용하여 모든 일을 할 수있는 쉬운 방법이 있는지 알고하실 수 있습니다.

해결법

  1. ==============================

    1.당신이 유형이 정적으로 알려져 있지 않은 HList에 flatMap 같은 작업을 수행 할 때마다, 당신은 작업이 해당 유형 실제로 사용할 수 있는지 (암시 적 매개 변수의 형태로) 증거를 제공해야합니다. 이 컴파일러는 FlatMapper의 실종에 대해 불평하는 이유 인스턴스를-는 방법을 알고하지 않는 것입니다 그들없이 임의 HList 이상 flatMap (정체성)에.

    당신이 유형이 정적으로 알려져 있지 않은 HList에 flatMap 같은 작업을 수행 할 때마다, 당신은 작업이 해당 유형 실제로 사용할 수 있는지 (암시 적 매개 변수의 형태로) 증거를 제공해야합니다. 이 컴파일러는 FlatMapper의 실종에 대해 불평하는 이유 인스턴스를-는 방법을 알고하지 않는 것입니다 그들없이 임의 HList 이상 flatMap (정체성)에.

    이런 종류의 일을 수행하기위한 청소기 방법은 사용자 정의 유형 클래스를 정의하는 것입니다. 볼품은 이미 레코드에 대한 ToMap 유형 클래스를 제공하고, 당신이 (가 중첩 된 경우 클래스에 재귀 적으로 작동하지 않습니다) 원하는 정보를 정확하게 제공하지 않지만 우리는 시작 지점으로 걸릴 수 있습니다.

    우리는 다음과 같은 것을 쓸 수 있습니다 :

    import shapeless._, labelled.FieldType, record._
    
    trait ToMapRec[L <: HList] { def apply(l: L): Map[String, Any] }
    

    이제 우리는 세 경우에 인스턴스를 제공해야합니다. 첫 번째 경우는 기본 케이스 - 레코드가-그리고 그것은 아래 hnilToMapRec에 의해 처리 것 비어 있습니다.

    우리가 레코드의 꼬리를 변환하는 방법을 알고있는 경우 두 번째 케이스의 경우, 우리는 머리를 우리는 또한 재귀 (여기 hconsToMapRec0를) 변환 할 수있는 무언가가 있음을 알고있다.

    마지막 경우는 있지만 ToMapRec 인스턴스가없는 헤드 (hconsToMapRec1)의 경우와 유사하다. 주 우리는이 인스턴스에 대해 제대로 우선 순위되어 있는지 확인하기 위해 LowPriority의 특성을 사용할 필요가 hconsToMapRec0-경우 우리가하지 않았다, 두 사람이 동일한 우선 순위를 가질 것, 우리가 모호한 인스턴스에 대한 오류를 얻을 것입니다.

    trait LowPriorityToMapRec {
      implicit def hconsToMapRec1[K <: Symbol, V, T <: HList](implicit
        wit: Witness.Aux[K],
        tmrT: ToMapRec[T]
      ): ToMapRec[FieldType[K, V] :: T] = new ToMapRec[FieldType[K, V] :: T] {
        def apply(l: FieldType[K, V] :: T): Map[String, Any] =
          tmrT(l.tail) + (wit.value.name -> l.head)
      }
    }
    
    object ToMapRec extends LowPriorityToMapRec {
      implicit val hnilToMapRec: ToMapRec[HNil] = new ToMapRec[HNil] {
        def apply(l: HNil): Map[String, Any] = Map.empty
      }
    
      implicit def hconsToMapRec0[K <: Symbol, V, R <: HList, T <: HList](implicit
        wit: Witness.Aux[K],
        gen: LabelledGeneric.Aux[V, R],
        tmrH: ToMapRec[R],
        tmrT: ToMapRec[T]
      ): ToMapRec[FieldType[K, V] :: T] = new ToMapRec[FieldType[K, V] :: T] {
        def apply(l: FieldType[K, V] :: T): Map[String, Any] =
          tmrT(l.tail) + (wit.value.name -> tmrH(gen.to(l.head)))
      }
    }
    

    마지막으로 우리는 편의를 위해 몇 가지 구문을 제공 :

    implicit class ToMapRecOps[A](val a: A) extends AnyVal {
      def toMapRec[L <: HList](implicit
        gen: LabelledGeneric.Aux[A, L],
        tmr: ToMapRec[L]
      ): Map[String, Any] = tmr(gen.to(a))
    }
    

    그리고 우리는 그것이 작동하는지 보여줄 수 :

    scala> p.toMapRec
    res0: Map[String,Any] = Map(address -> Map(zip -> 10000, street -> Jefferson st), name -> Tom)
    

    이 중첩 된 경우 클래스 등리스트, 터플에 유형에 대해 작동하지 않습니다,하지만 당신은 아주 똑 바르게 이러한 경우에 그것을 확장 할 수 있습니다.

  2. ==============================

    2.나는 트래비스 브라운에 의해 제공되는 접근 방식에 문제가 있습니다. 중첩의 경우 클래스 중 일부는 https://scalafiddle.io/sf/cia2jTa/0지도로 변환되지 않습니다.

    나는 트래비스 브라운에 의해 제공되는 접근 방식에 문제가 있습니다. 중첩의 경우 클래스 중 일부는 https://scalafiddle.io/sf/cia2jTa/0지도로 변환되지 않습니다.

    답은 여기에서 발견되었다. 용액을 보정 단지 랩 ToMapRec [T] 레이지 [ToMapRec [T]에 내재 된 파라미터이다. https://scalafiddle.io/sf/cia2jTa/1 바이올린 수정

  3. from https://stackoverflow.com/questions/31633563/converting-nested-case-classes-to-nested-maps-using-shapeless by cc-by-sa and MIT license