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