Scala:在运行时替换方法

时间:2015-08-16 22:52:45

标签: scala testing reflection runtime scala-macros

我们说我有一个班级

class Original {
  def originalMethod = 1
}

现在,让我们说我有一个实例

val instance = new Original

现在是否可以在运行时对instance执行某些操作以使用其他方法替换originalMethod? (授予签名保持不变)

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

修改 我无法致电new Original。我只有一个现有的实例,我必须修改它。

编辑2 (@Aleksey Izmailov回答)这是一个很好的解决方案,但并不是我正在寻找的。我在测试方面考虑更多 - 写一个类"通常",而不指定函数作为变量而不是方法

PS。当我试图模仿Mockito间谍时,我偶然发现了这个问题

2 个答案:

答案 0 :(得分:2)

似乎你必须恢复变异,因为你不能有新的实例和行为必须改变。这可能是最简单的选项(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                       ^

将其替换为新功能:

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

现在你正在获得新的行为:

scala> obj.originalMethod()
res2: Int = 2

有趣的是,您无法使用此类的通用版本进行默认实现,因为除非您将其更改为Unit或部分函数,​​否则您无法使用默认值。

以下是它的通用版本:

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

答案 1 :(得分:1)

这在JVM上是不可能的 - 无论是Java还是Scala - 都不是你所要求的。

参见例如In Java, given an object, is it possible to override one of the methods?

使用Scala而不是Java不会获得额外的杠杆作用,因为类和方法在Scala中的工作原理基本与Java相同。 (这是出于性能和互操作的原因。)