在Scala中,如何把对象的值到地图[字符串,字符串]?(In scala, how to turn

2019-08-01 06:16发布

比方说,我有这个类

case class Test (id: Long, name: String)

这个类的一个实例:

Test :
id -> 1
name -> toto

我想创建一个地图[字符串,字符串]如下:

Map( "id" -> "1", "name" -> "toto")

我的问题是:有没有办法把测试的这种情况下进入地图[字符串,字符串]? 我想避免使用的方法,因为这一个:

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
}

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

Answer 1:

是的,它是可能的。 由于斯卡拉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其实例。



Answer 2:

如果你想有一个类型安全的实现你面对的是越来越令人难以置信的经常性StackOverflow上和问题的主题是不平凡的。

解决这个问题的方法之一是使用反射(如建议),但我个人更喜欢使用类型系统和implicits。

有一个著名的图书馆,是由一个非常聪明的家伙开发,谁会让你执行高级操作,如打开任何情况下类为类型安全的异构列表,或创建heteregeneous地图,它可以被用来实现“可延展的记录”。 该库被称为无形的,在这里一个例子:

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)
}

书行为类似类型安全地图可以使用索引对象作为密钥。 如果您有兴趣了解更多,一个很好的切入点可能是这个职位:

是HLists无非就是写一个元组的令人费解的方式吗?



Answer 3:

开始Scala 2.13case classes (为实现Product )提供有productElementNames方法,它返回了自己的字段名称的迭代器。

通过压缩和解与获得的域值的域名productIterator我们可以得到一般相关联的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")


文章来源: In scala, how to turn object's values into Map[String, String]?
标签: scala