Scala映射到任意类(Scala反射)
如果我有一张Scala地图Scala映射到任意类(Scala反射),scala,reflection,deserialization,scala-collections,Scala,Reflection,Deserialization,Scala Collections,如果我有一张Scala地图 val map = Map("a" -> true, "b" -> "hello" "c" -> 5) 是否有一种方法可以将其转换为对象(case类、regular类、任何真正的对象),以便像这样访问字段: val obj = map.toObj println(obj.a) println(obj.b) 在不知道参数将是什么的情况下提前 或者更好,它可以是我当前使用的类的实例变量吗 所以我
val map = Map("a" -> true,
"b" -> "hello"
"c" -> 5)
是否有一种方法可以将其转换为对象(case类、regular类、任何真正的对象),以便像这样访问字段:
val obj = map.toObj
println(obj.a)
println(obj.b)
在不知道参数将是什么的情况下提前
或者更好,它可以是我当前使用的类的实例变量吗
所以我真的可以
println(a)
println(b)
查看
动态:
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
:
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是一种编译器功能,它将所有字段/方法调用转换为对*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])
}
我希望您通过问这个问题来理解,当您依赖运行时数据时,您将失去所有编译时保证。如果这是您真正想要的,那么您可以信赖:
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])
}
你真的不知道任何提前的参数吗?或者你会得到一组有限的选项中的一个?我不明白你怎么可能不知道参数名,然后期望转到println(a)
或obj.a
,因为这似乎要求你知道它是a
!你真的不知道任何提前的参数吗?或者你会得到一组有限的选项中的一个?我不明白你怎么可能不知道参数名,然后期望转到println(a)
或obj.a
,因为这似乎要求你知道它是a
!当我运行上一个示例时,我得到一个匹配错误
(2.10.3)。如果使用[java.lang.Boolean]
而不是[Boolean]
,则它可以工作。有什么方法可以使用[Boolean]
吗?我修复了匹配错误
,但无法说明为什么正常的Boolean
参数在2.10中不起作用。这似乎是一个bug,但我无法尝试,因为我没有安装2.10。当我运行上一个示例时,我得到一个匹配错误
(2.10.3)。如果使用[java.lang.Boolean]
而不是[Boolean]
,则它可以工作。有什么方法可以使用[Boolean]
吗?我修复了匹配错误
,但无法说明为什么正常的Boolean
参数在2.10中不起作用。这似乎是一个错误,但我不能尝试它,因为我没有一个2.10安装在这里。