比方说,我有这个类
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
}
那可能吗 ? 如果你有很好的例子/链接,我很感兴趣。
是的,它是可能的。 由于斯卡拉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
其实例。
如果你想有一个类型安全的实现你面对的是越来越令人难以置信的经常性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无非就是写一个元组的令人费解的方式吗?
开始Scala 2.13
, case 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")