2017-10-06 3 views
0

J'essaie cela et il fonctionne:LabelledGenerid.Aux implicite non disponible lors de l'utilisation type générique dans le corps de la fonction

` 
    case class Foo(name: String)

class Morphic(map: Map[String, Any]) { def add(k: String, v: Any) = { new Morphic((map + (k -> v))) } def to[T](): T = { def toClass[A]: ToCase[A] = new ToCase[A] // This is class to convert from Map to case class val res = toClass[Foo].from(map).get // <-- problem is here - cannot use T res.asInstanceOf[T] } } object testApp extends App { var m = new Morphic(Map[String, Any]()) var m1 = m.add("name", "john") println(m1.to[Foo]) }

je devrais utiliser T au lieu de Foo dans val res = toClass[T].from(map).get mais il ne compile pas dire implicite il manque

toClass[T].from est une fonction de création d'un type de classe de cas Carte

donné Comment puis-je faire que implicites (et peut-être d'autres sur lesquels repose .from) disponible?

J'ai essayé def to[T, H <: HList]()(implicit gen: LabelledGeneric.Aux[A, H]) = ... mais je besoin de spécifier les types lors de l'appel .to et je ne peux pas comprendre ce qu'il faut préciser H

Merci

+0

Ecrivez votre 'ToCase'. –

+0

Si je comprends bien, 'toClass [Foo] .from (map)' est de type 'Foo'. Où est '.get' dans' toClass [Foo] .from (map) .get'? Avez-vous '.get' dans' Foo'? –

+0

Ah, peut-être, ce n'est pas "Foo" mais "Option [Foo]". –

Répondre

1

Vous pouvez transformer un Map en HList, et puis le HList dans T:

import shapeless.{::, HList, HNil, LabelledGeneric, Witness} 
import shapeless.labelled._ 

case class Foo(name: String) 

trait MapToHList[L <: HList] { 
    def apply(map: Map[String, Any]): Option[L] 
} 
object MapToHList { 
    implicit object hNilMapToHList extends MapToHList[HNil] { 
    override def apply(map: Map[String, Any]): Option[HNil] = Some(HNil) 
    } 

    implicit def hConsMapToHList[K <: Symbol, V, T <: HList](implicit 
                  mapToHList: MapToHList[T], 
                  witness: Witness.Aux[K] 
                 ): MapToHList[FieldType[K, V] :: T] = 
    new MapToHList[FieldType[K, V] :: T] { 
     override def apply(map: Map[String, Any]): Option[FieldType[K, V] :: T] = { 
     val str = witness.value.toString.tail 
     for { 
      v <- map.get(str) 
      t <- mapToHList(map) 
     } yield field[K](v.asInstanceOf[V]) :: t 
     } 
    } 
} 

trait ToCase[A] { 
    def from(map: Map[String, Any]): Option[A] 
} 
object ToCase { 
    implicit def mkToCase[A, L <: HList](implicit 
             gen: LabelledGeneric.Aux[A, L], 
             mapToHList: MapToHList[L] 
            ): ToCase[A] = 
    new ToCase[A] { 
     override def from(map: Map[String, Any]): Option[A] = mapToHList(map).map(gen.from) 
    } 
} 


class Morphic(map: Map[String, Any]) { 

    def add(k: String, v: Any) = { 
    new Morphic((map + (k -> v))) 
    } 

    def to[T](implicit toCase: ToCase[T]): T = toCase.from(map).get 

} 

object testApp extends App { 
    var m = new Morphic(Map[String, Any]()) 
    var m1 = m.add("name", "john") 
    println(m1.to[Foo]) // Foo(john) 
} 

J'ai essayé def to[T, H <: HList]()(implicit gen: LabelledGeneric.Aux[A, H]) ... mais alors je dois spécifier les deux types lors de l'appel .to et je ne peux pas comprendre ce qu'il faut préciser H

Vous pouvez l'appeler comme m1.to[Foo, FieldType[Witness.`'name`.T, String] :: HNil]() ou m1.to[Foo, Record.`'name -> String`.T]().

+0

C'est parfait, merci. Mon code .from était similaire au vôtre mais ce qui manquait, c'est l'ensemble du wrapper implicite. Je ne comprends toujours pas comment cela fonctionne, c'est-à-dire ma mauvaise compréhension de tout ce qui est implicite, je vais maintenant m'assurer que je l'obtiens complètement :) – r3stle55

+0

@ r3stle55 Bonne chance. Si vous êtes satisfait de la réponse, vous pouvez l'accepter. –