Scala:在运行时替换方法

Scala:在运行时替换方法,scala,testing,reflection,runtime,scala-macros,Scala,Testing,Reflection,Runtime,Scala Macros,假设我有一节课 class Original { def originalMethod = 1 } 现在,假设我有一个例子 val instance = new Original 现在是否可以在运行时对实例执行一些操作,以使用不同的方法替换原始方法?(授权签名保持不变) 例如,现在,当调用instance.originalMethod时,以下代码将被调用println(“test”);1 编辑 我不能调用新的原始版本。我只是有一个现有的实例,我必须修改它 编辑2 (@Aleksey-Iz

假设我有一节课

class Original {
  def originalMethod = 1
}
现在,假设我有一个例子

val instance = new Original
现在是否可以在运行时对
实例
执行一些操作,以使用不同的方法替换
原始方法
?(授权签名保持不变)

例如,现在,当调用
instance.originalMethod
时,以下代码将被调用
println(“test”);1

编辑 我不能调用新的原始版本。我只是有一个现有的实例,我必须修改它

编辑2
(@Aleksey-Izmailov-answer)这是一个很好的解决方案,但并不是我想要的。我更多地考虑测试——编写一个“正常”的类,而不将函数指定为变量而不是方法


顺便说一句,我在试图模仿Mockito间谍时偶然发现了这个问题,因为你不能有新的实例,行为必须改变,所以你似乎必须回到变异。以下可能是最简单的选项(REPL):

将函数存储为可变字段:

scala> class Original {
     |   var originalMethod = () => 1
     | }
defined class Original

scala> val obj = new Original
obj: Original = Original@66ac5762
这是一个不需要任何东西的函数,您需要对其调用
apply
()
,以获得结果

scala> obj.originalMethod
res0: () => Int = <function0>

scala> obj.originalMethod()
res1: Int = 1                       ^
有趣的是,您不能使用该类的泛型版本实现默认值,因为除非您将其更改为
Unit
或partial function,否则没有可以使用的默认值

以下是它的通用版本:

scala> class Original[T] {                                                               
     |   var originalMethod: () => T = null                                              
     | }                                                                                 
defined class Original                                                                   

scala> val genImpl = new Original[Int] { originalMethod = () => 111 }                    
genImpl: Original[Int] = $anon$1@6b04acb2                                                       

scala> genImpl.originalMethod()                                                          
res8: Int = 111                                                                          

scala> genImpl.originalMethod = () => 222
genImpl.originalMethod: () => Int = <function0>

scala> genImpl.originalMethod()
res9: Int = 222
scala>类原始[T]{
|var originalMethod:()=>T=null
| }                                                                                 
定义类原始
scala>val-genImpl=new-Original[Int]{originalMethod=()=>111}
genImpl:Original[Int]=$anon$1@6b04acb2                                                       
scala>genImpl.originalMethod()
res8:Int=111
scala>genImpl.originalMethod=()=>222
genImpl.originalMethod:()=>Int=
scala>genImpl.originalMethod()
res9:Int=222

这在JVM上是不可能的,无论是Java还是Scala,都不可能以您要求的方式实现

见例


使用Scala而不是Java并不能获得额外的优势,因为类和方法在Scala中的工作原理与Java相同。(这样做是出于性能和互操作的原因。)

在您的情况下是否可以使用聚合?聚合是什么意思?这是一个很好的解决方案,但不是我想要的。我考虑的更多的是测试——编写一个“正常”的类,而不将函数指定为变量而不是方法。也许你可以使用宏重写AST,这样做本质上会做同样的事情,但会对用户隐藏细节。
scala> obj.originalMethod()
res2: Int = 2
scala> class Original[T] {                                                               
     |   var originalMethod: () => T = null                                              
     | }                                                                                 
defined class Original                                                                   

scala> val genImpl = new Original[Int] { originalMethod = () => 111 }                    
genImpl: Original[Int] = $anon$1@6b04acb2                                                       

scala> genImpl.originalMethod()                                                          
res8: Int = 111                                                                          

scala> genImpl.originalMethod = () => 222
genImpl.originalMethod: () => Int = <function0>

scala> genImpl.originalMethod()
res9: Int = 222