2015-11-21 86 views
1

作爲一個練習,我試圖看看我是否可以採取List[Any]並將其「鑄造」爲使用無形的案例類。將列表轉換爲案例類

A的什麼,我想實現非常簡單的例子:

case class Foo(i: Int, j: String) 
val foo: Option[Foo] = fromListToCaseClass[Foo](List(1:Any, "hi":Any)) 

這裏是我如何塑造我的解決方案(這可能是非常關):

def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map(x => Generic[CC].from(x)) 

這裏是我的推理:

我知道你可以從案例類轉到HList [T](CC - > HList [T]);其中T是HList的類型。我也知道,只要知道HList的類型,就可以從列表(列表 - >選項[HList])創建一個HList。最後,我知道你可以從一個HList到一個案例類(HList→CC)。

CC -> HList[T] 
list -> Option[HList[T]] -> Option[CC] 

我想知道這是否有意義或如果我在這裏的方式。我們能做這項工作嗎?還有其他建議嗎?謝謝!

回答

5

這可以非常直接地使用無形的GenericFromTraversable類型類來完成,

import scala.collection.GenTraversable 
import shapeless._, ops.traversable.FromTraversable 

class FromListToCaseClass[T] { 
    def apply[R <: HList](l: GenTraversable[_]) 
    (implicit gen: Generic.Aux[T, R], tl: FromTraversable[R]): Option[T] = 
     tl(l).map(gen.from) 
} 
def fromListToCaseClass[T] = new FromListToCaseClass[T] 

(由於Scala的尷尬,這裏有一些意外的複雜性當涉及混合明確的和推斷的類型參數時:我們想明確地指定T,但是爲我們推斷了R)。

樣品REPL會話...

scala> case class Foo(i: Int, j: String) 
defined class Foo 

scala> fromListToCaseClass[Foo](List(23, "foo")) 
res0: Option[Foo] = Some(Foo(23,foo)) 

scala> fromListToCaseClass[Foo](List(23, false)) 
res1: Option[Foo] = None 
2

你可以用無形做到這一點的方式如下:

import shapeless._ 

trait Creator[A] { def apply(list:List[Any]): Option[A] } 

object Creator { 
    def as[A](list: List[Any])(implicit c: Creator[A]): Option[A] = c(list) 

    def instance[A](parse: List[Any] => Option[A]): Creator[A] = new Creator[A] { 
    def apply(list:List[Any]): Option[A] = parse(list) 
    } 

    def arbitraryCreate[A] = instance(list => list.headOption.map(_.asInstanceOf[A])) 

    implicit val stringCreate = arbitraryCreate[String] 
    implicit val intCreate = arbitraryCreate[Int] 
    implicit val hnilCreate = instance(s => if (s.isEmpty) Some(HNil) else None) 

    implicit def hconsCreate[H: Creator, T <: HList: Creator]: Creator[H :: T] = 
instance { 
    case Nil => None 
    case list => for { 
    h <- as[H](list) 
    t <- as[T](list.tail) 
    } yield h :: t 
} 

implicit def caseClassCreate[C, R <: HList](
    implicit gen: Generic.Aux[C, R], 
    rc: Creator[R]): Creator[C] = 
    instance(s => rc(s).map(gen.from)) 
} 

而且

val foo:Option[Foo] = Creator.as[Foo](List(1, "hi")) 
+3

很好的嘗試,但是你錯過了'Typeable'和'FromTraversable'其對付你想用'Creator'來解決問題。 –