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) 在不知道参数将是什么的情况下提前 或者更好,它可以是我当前使用的类的实例变量吗 所以我

如果我有一张Scala地图

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安装在这里。