如何将Map转换为Scala中的case类? [英] How can I transform a Map to a case class in Scala?

查看:828
本文介绍了如何将Map转换为Scala中的case类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个 Map [String,String](url - >xxx,title - >yyy)一种将其转换为案例类Image(url:String,title:String)

If I have a Map[String,String]("url" -> "xxx", "title" -> "yyy"), is there an way to generically transform it into a case class Image(url:String, title:String)?

可以写一个帮助器:

object Image{
  def fromMap(params:Map[String,String]) = Image(url=params("url"), title=params("title"))
}

但是有一种方法可以一次性地将地图写入任何案例类别。

but is there a way to generically write this once for a map to any case class?

推荐答案

是一些安全的选择,你可以做,如果你只是想缩短你的代码。伴随对象可以被当作一个函数,所以你可以使用这样的东西:

First off, there are some safe alternatives you could do if you just want to shorten your code. The companion object can be treated as a function so you could use something like this:

def build2[A,B,C](m: Map[A,B], f: (B,B) => C)(k1: A, k2: A): Option[C] = for {
  v1 <- m.get(k1)
  v2 <- m.get(k2)
} yield f(v1, v2)

build2(m, Image)("url", "title")

这将返回一个包含结果的选项。或者,您可以使用Scalaz中的 ApplicativeBuilder ,它在内部做的几乎相同,但更好的语法:

This will return an option containing the result. Alternatively you could use the ApplicativeBuilders in Scalaz which internally do almost the same but with a nicer syntax:

import scalaz._, Scalaz._
(m.get("url") |@| m.get("title"))(Image)

如果你真的需要通过反射做这个最简单的方法是使用Paranamer(作为Lift框架)。 Paranamer可以通过检查字节码来恢复参数名称,因此存在性能损失,并且由于类加载器问题(例如REPL),它不能在所有环境中工作。如果你限制自己只有 String 构造函数参数的类,那么你可以这样做:

If you really need to do this via reflection then the easiest way would be to use Paranamer (as the Lift-Framework does). Paranamer can restore the parameter names by inspecting the bytecode so there is a performance hit and it will not work in all environments due to classloader issues (the REPL for example). If you restrict yourself to classes with only String constructor parameters then you could do it like this:

val pn = new CachingParanamer(new BytecodeReadingParanamer)

def fill[T](m: Map[String,String])(implicit mf: ClassManifest[T]) = for {
  ctor <- mf.erasure.getDeclaredConstructors.filter(m => m.getParameterTypes.forall(classOf[String]==)).headOption
  parameters = pn.lookupParameterNames(ctor)
} yield ctor.newInstance(parameters.map(m): _*).asInstanceOf[T]

val img = fill[Image](m)

(注意,此示例可以选择一个默认构造函数,因为它不会检查您要执行的参数计数)

(Note that this example can pick a default constructor as it does not check for the parameter count which you would want to do)

这篇关于如何将Map转换为Scala中的case类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆