在scala中,如何将对象的值转换为Map [String,String]?

ale*_*dre 15 scala

让我们说我有这门课

case class Test (id: Long, name: String)
Run Code Online (Sandbox Code Playgroud)

和这个类的一个实例:

Test :
id -> 1
name -> toto
Run Code Online (Sandbox Code Playgroud)

我想创建一个Map [String,String]如下:

Map( "id" -> "1", "name" -> "toto")
Run Code Online (Sandbox Code Playgroud)

我的问题是:有没有办法将这个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
}
Run Code Online (Sandbox Code Playgroud)

如果在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
}
Run Code Online (Sandbox Code Playgroud)

那可能吗 ?如果你有很好的例子/链接,我很感兴趣.

Nik*_*kov 21

是的,这是可能的.从Scala 2.10开始,您可以使用反射.

假设你有:

val test = Test(23423, "sdlkfjlsdk")
Run Code Online (Sandbox Code Playgroud)

以下内容将为您提供所需内容:

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
Run Code Online (Sandbox Code Playgroud)

简单地迭代.productIterator在其实例上使用案例类的字段值.


Edm*_*984 11

您正在处理的主题在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)
}
Run Code Online (Sandbox Code Playgroud)

Book的行为类似于可以使用对象作为键索引的类型安全映射.如果您有兴趣了解更多信息,可能会有一个很好的切入点:

HLists只不过是一种复杂的编写元组的方式吗?