scala - Scala 中 Java 反射的类型安全用法

标签 scala reflection scala-macros scala-cats

我正在尝试使用 Java 反射在运行时替换对象字段的值,但以类型安全的方式。

假设我们有以下对象。

import cats.Eval

object Foo {
  val bar: Eval[Int] = Eval.later(throw new Exception)
}

我们希望在运行时更改 Foo.bar 的值。我们可以使用普通的 Java 反射轻松定义以下方法:

import java.lang.reflect.Field

def usingJavaReflection[T](targetObject: AnyRef, fieldName: String)(newValue: T): Unit = {
  val field = targetObject.getClass.getDeclaredField(fieldName)
  field.setAccessible(true)
  field.set(targetObject, newValue)
}

// usage
usingJavaReflection(Foo, "bar")(Eval.now(42))

现在的问题是:如何以更类型安全的方式做到这一点?

def usingJavaReflectionButTypesafe[T](field: T)(newValue: T): Unit = ???

// intended usage
usingJavaReflectionButTypesafe(Foo.bar)(Eval.now(42))

这意味着能够做一些事情:

  1. Foo.bar 不应被评估
  2. 相反,Foo.bar 应分解为目标对象 Foo 和字段 "bar"
  3. Foo.bar 的类型应与 newValue 相同

额外问题:如果这是可能的,如何使其适用于 Scala 2.11、2.12 和 2.13。我只是无法理解哪些 Scala 宏技术可以在哪些版本的 Scala 中安全使用以及如何使用。

最佳答案

尝试

def usingJavaReflectionButTypesafe[T](field: => T)(newValue: T): Unit = macro impl[T]

def impl[T: c.WeakTypeTag](c: blackbox.Context)(field: c.Tree)(newValue: c.Tree): c.Tree = {
  import c.universe._
  field match {
    case q"$expr.$tname" =>
      q"usingJavaReflection($expr, ${tname.toString})($newValue)"
  }
}

关于scala - Scala 中 Java 反射的类型安全用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57499158/

相关文章:

scala - Scala宏可以打印代码?

scala - 一次处理每个分区中的每个分区和每一行

scala - 从线程模型到参与者模型的转变

scala - 安装了 Scala 和 sbt 插件的 NetBeans 8.0 可以创建 sbt 项目吗?

java - 避免使用 if 语句创建对象

scala - 在scala宏中推断树的类型

java - playframework模板报价/报价规则

c# - 动态创建代理类

java - 内部类中的两个声明的构造函数

scala - 如何确定传递给宏的表达式是否始终产生相同的值?