假设我有这个课程
case class Test (id: Long, name: String)
和这个类的一个实例:
Test :
id -> 1
name -> toto
我想创建一个Map [String,String],如下所示:
Map( "id" -> "1", "name" -> "toto")
我的问题是:有没有办法将此Test实例转换为Map [String,String]?我想避免使用这样的方法:
def createMap(instance: Test): Map[String, String] = {
val map = new Map[String, String]
map.put("id", instance.id.toString)
map.put("name", instance.name)
map
}
如果在Scala中没有方法可以这样做,有没有办法迭代类属性?也许我可以创建一个通用函数:
def createMap(instance: T): Map[String, String] = {
val map = new Map[String, String]
//pseudocode
for ((name, value) <- instance.getClassProperties.getValues) {
case value.isInstanceOf[String] : map.push(name, value)
case _ : map.push(name, value.toString)
}
map
}
这可能吗?如果你有很好的例子/链接,我很感兴趣。
答案 0 :(得分:20)
是的,这是可能的。从Scala 2.10开始,您可以使用反射。
假设你有:
val test = Test(23423, "sdlkfjlsdk")
以下内容可为您提供所需内容:
import reflect.runtime.universe._
import reflect.runtime.currentMirror
val r = currentMirror.reflect(test)
r.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
.map(r => r.symbol.name.toString.trim -> r.get.toString)
.toMap
简单地迭代案例类的字段值,在其实例上使用.productIterator
。
答案 1 :(得分:10)
您正在处理的主题在StackOverFlow上变得非常复杂,如果您想要一个类型安全的实现,问题就不容小觑了。
解决问题的一种方法是使用反射(如建议的那样),但我个人更喜欢使用类型系统和暗示。
有一个着名的库,由一个非常聪明的人开发,允许你执行高级操作,例如将任何案例类转换为类型安全的异构列表,或者创建可用于实现“可扩展记录”的异常映射”。该库名为Shapeless,这里有一个例子:
object RecordExamples extends App {
import shapeless._
import HList._
import Record._
object author extends Field[String] { override def toString = "Author" }
object title extends Field[String] { override def toString = "Title" }
object id extends Field[Int] { override def toString = "ID" }
object price extends Field[Double] { override def toString = "Price" }
object inPrint extends Field[Boolean] { override def toString = "In print" }
def printBook[B <: HList](b : B)(implicit tl : ToList[B, (Field[_], Any)]) = {
b.toList foreach { case (field, value) => println(field+": "+value) }
println
}
val book =
(author -> "Benjamin Pierce") ::
(title -> "Types and Programming Languages") ::
(id -> 262162091) ::
(price -> 44.11) ::
HNil
printBook(book)
// Read price field
val currentPrice = book.get(price) // Static type is Double
println("Current price is "+currentPrice)
println
// Update price field, relying on static type of currentPrice
val updated = book + (price -> (currentPrice+2.0))
printBook(updated)
// Add a new field
val extended = updated + (inPrint -> true)
printBook(extended)
// Remove a field
val noId = extended - id
printBook(noId)
}
Book的行为类似于可以使用对象作为键索引的类型安全映射。如果您有兴趣了解更多信息,可能会有一个很好的切入点:
Are HLists nothing more than a convoluted way of writing tuples?
答案 2 :(得分:0)
Product
的开始为Scala 2.13
,case classes
(作为productElementNames
的实现)提供了productIterator
方法,该方法返回其字段名称上的迭代器。
通过将字段名称与通过http://www.opa.kg/uploads/posts/2009-08/1251278848_podborochka-kartinok_37355_s__22.jpg获得的字段值进行压缩,我们可以通用地获取关联的Map[String, Any]
,并通过将值与toString
关联的Map[String, String]
进行映射:
// case class Test(id: Long, name: String)
// val x = Test(1, "todo")
(x.productElementNames zip x.productIterator.map(_.toString)).toMap
// Map[String,String] = Map("id" -> "1", "name" -> "todo")