如果我有Scala地图
val map = Map("a" -> true,
"b" -> "hello"
"c" -> 5)
有没有办法可以将它转换为对象(case类,常规类,真正的任何东西),以便我可以像这样访问字段:
val obj = map.toObj
println(obj.a)
println(obj.b)
没有知道参数会提前是什么?
或者甚至更好,它可以是我正在使用的类的实例变量吗?
所以我真的可以
println(a)
println(b)
答案 0 :(得分:2)
查看Dynamic
:
import scala.language.dynamics
class Wrapper(m: Map[String, Any]) extends Dynamic {
def selectDynamic(name: String) = {
m(name)
}
}
object Demo {
def main(args: Array[String]) {
val map = Map("a" -> true,
"b" -> "hello",
"c" -> 5)
val w = new Wrapper(map)
println(w.a)
println(w.b)
}
}
Dynamic
为您提供“按需提供的属性”。
但它不是类型安全的。在上面的代码段中,如果您尝试访问地图中的不存在的密钥,则会引发NoSuchElementException
。并且您获得了Any
类型,因此您必须在呼叫方旁使用asInstanceOf
。
Dynamic
还有其他方法,因此请仔细查看Dynamic
答案 1 :(得分:2)
我希望您通过提出这个问题来理解,当您依赖运行时数据时,您将失去所有编译时保证。如果这真的是你想要的那么你可以依靠Dynamic:
object X extends App {
import scala.language.dynamics
class D(fields: Map[String, Any]) extends Dynamic {
def selectDynamic(str: String): Any =
fields.getOrElse(str, throw new NoSuchFieldException(str))
}
val fields = Map[String, Any]("a" -> true, "b" -> "hello")
val obj = new D(fields)
println(obj.a)
println(obj.b)
}
Dynamic是一种编译器功能,可将所有字段/方法调用转换为对*Dynamic*
方法的调用。因为编译器不能了解你的程序(它应该怎么做?),你在这里得到的返回类型是Any
,当你调用一个不存在的字段/方法时,你会在运行时得到一个异常而不是编译时错误。当已知编译时的某些字段/方法时,您可以将Dynamic与宏组合以至少进行一些编译时检查(这种方法在链接的答案中描述)。
除此之外,这是您可以在Scala中启用的唯一语法。如果返回类型对您很重要,您至少可以将它们添加为类型参数:
object X extends App {
import scala.language.dynamics
class D(fields: Map[String, Any]) extends Dynamic {
def selectDynamic[A : reflect.ClassTag](str: String): A =
fields.get(str) match {
case Some(f: A) => f
case _ => throw new NoSuchFieldException(str)
}
}
val fields = Map[String, Any]("a" -> true, "b" -> "hello")
val obj = new D(fields)
println(obj.a[Boolean])
println(obj.b[String])
}