【问题标题】:Generic class wrapper in scalaScala中的通用类包装器
【发布时间】:2021-10-05 19:51:05
【问题描述】:

您好,我想在 scala 中创建一个通用包装器,以跟踪任何类型的值的变化。到目前为止,我不知道/还没有找到任何其他方法,我正在考虑创建一个类,我一直在尝试使用 Dynamic,但它有一些限制。

case class Wrapper[T](value: T) extends Dynamic {
  private val valueClass = value.getClass

  def applyDynamic(id: String)(parameters: Any*) = {
    val objectParameters = parameters map (x => x.asInstanceOf[Object])
    val parameterClasses = objectParameters map (_.getClass)
    val method = valueClass.getMethod(id, parameterClasses:_*)
    val res = method.invoke(value, objectParameters:_*)

    // TODO: Logic that will eventually create some kind of event about the method invoked.

    new Wrapper(res)
  }
}

使用这段代码时,我在两个整数上调用 plus("+") 方法时遇到了麻烦,我不明白为什么。 Int 类中没有“+”方法吗?当我尝试使用两种 Wrapper/Int 进行添加时遇到的错误是:

var wrapped1 = Wrapper(1)
wrapped1 = wrapped1 + Wrapper[2] // or just 2

type mismatch;
 found   : Wrapper[Int]/Int
 required: String

为什么它需要一个字符串?

如果可能的话,能够无缝地使用 Wrapper[T] 和 T 方法也很好,例如

val a = Wrapper[Int](1)
val b = Wrapper[Int](2)
val c = 3

a + b // Wrapper[Int].+(Wrapper[Int])
a + c // Wrapper[Int].+(Int)
c + a // Int.+(Wrapper[Int]) 

【问题讨论】:

  • 您最终会发现原语在 Scala 中是未装箱的。我已经写了一篇 20 页的论文,关于您正在尝试做的事情,这只是冰山一角。根据你想走多远,你会遇到一百万个不同的问题。 tl;dr 如果不编写编译器插件来显式改变某些东西的工作方式,这实际上是不可能完全扩展的。

标签: scala


【解决方案1】:

好吧,如果您尝试创建一个可以更改所需值的代理,那么如果没有代理,您可能会失败(https://dzone.com/articles/java-agent-1),因为它会强制您对接受最终类和原语的字节码进行代码修改以接受你的代理而不是那个,它不仅需要拦截“公正类”的变化,还需要拦截所有成员类别并产生价值起源分析等等。这绝不是小问题。

另一种方法是通过比较某些执行点中的类来产生案例类的差异,并且有类似的通用实现,它使用派生来计算差异:https://github.com/ivan71kmayshan27/ShapelesDerivationExample 我相信您可以使用 magnolia 提供更简单的解决方案。实际上,除非您编写自己的宏并且在有序和无序集合方面遇到一些问题,否则这个不能仅用于类。

【讨论】:

  • 前者不行。 Java 的元编程 API 与 Scala 中的很多东西发生冲突。即使在 Java 中,代理也只能使用接口而不是具体类。我不确定你说的第二部分是什么意思。我的理解是 OP 想要劫持方法调用以了解价值如何演变。最简单的例子是,这对原语没有任何用处。还是我误解了你的话?
  • 前者会起作用,因为 scala 代码会像其他所有代码一样转换为字节码,这就是为什么您可以使用来自 kotlin 和 java 的 scala 代码,因此您可以使用允许字节码处理器的 API 对其进行修改。你仍然需要考虑一些 scala 的事情,但是说“它根本不起作用”大多是不正确的。第二种方法是使用简单的值差异而不是间谍。
  • 对于 Scala 3 来说并不完全正确,但是是的,这超出了这个问题的范围。我只是离开了链接的文章。我只是想说那里提出的方法不能捕获所有的 Scala 结构。有很多方法可以做到,但很快就会失控。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-12
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多