如何在调用其他方法时隐式调用方法?

时间:2013-11-14 06:27:01

标签: scala

我有一个定义私有维护方法 synch 的类,我想在调用该类的任何其他方法时始终调用它。这样做的经典方法当然是:

def method1 = {
    synch
    // ... do stuff
}

def method2 = {
    synch
    // ... do other stuff
}

但是,有没有办法隐式地完成这个,所以我不必像上面那样明确地调用它?

修改

如果可以这样做,是否也可以定义我是否希望 synch 方法在之后之前 彼此的方法?

3 个答案:

答案 0 :(得分:3)

您可以使用def macrosDynamic创建自定义包装器,如下所示:

import scala.reflect.macros.Context
import scala.language.experimental.macros

def applyDynamicImplementation(c: Context)(name: c.Expr[String])(args: c.Expr[Any]*) : c.Expr[Any] = {
  import c.universe._

  val nameStr = name match { case c.Expr(Literal(Constant(s: String))) => s }
  if (nameStr != "sync")
    c.Expr[Any](q"""{
      val res = ${c.prefix}.t.${newTermName(nameStr)}(..$args)
      ${c.prefix}.t.sync
      res
    }""")
  else
    c.Expr[Any](q"""${c.prefix}.t.sync""")
}

import scala.language.dynamics

class SyncWrapper[T <: { def sync(): Unit }](val t: T) extends Dynamic {
  def applyDynamic(name: String)(args: Any*): Any = macro applyDynamicImplementation
}

您必须使用compiler plugin进行quasiquotes。如果您想在方法之前致电sync,只需切换val res = ...${c.prefix}.t.sync行。

用法:

class TestWithSync {
  def test(a: String, b: String) = {println("test"); a + b}
  def test2(s: String) = {println("test2"); s}
  def sync() = println("sync")
}

val w = new SyncWrapper(new TestWithSync)

scala> w.test("a", "b")
test
sync
res0: String = ab

scala> w.test2("s")
test2
sync
res1: String = s

scala> w.invalidTest("a", "b")
<console>:2: error: value invalidTest is not a member of TestWithSync
              w.invalidTest("a", "b")
                           ^

答案 1 :(得分:0)

您可以使用字节码重写或使用macro annotations来完成此操作。两者都会非常复杂。有些事情需要考虑:

  1. 您是否也希望这种情况发生在继承的方法上?

  2. 如果synch调用此类的任何其他方法,您将获得无限循环。

答案 2 :(得分:0)

隐式定义是指允许编译器插入程序以修复其任何类型错误的定义。例如,如果x + y未键入check,则编译器可能将其更改为convert(x)+ y,其中convert是一些可用的隐式转换。如果转换将x更改为具有+方法的内容,则此更改可能会修复程序,以便键入检查并正确运行。如果转换真的只是一个简单的转换函数,那么将它从源代码中删除可能是一个澄清。

基本上implicit用于隐式转换,所以我尝试使用一个例子,我认为它会对你有所帮助:

scala> class c{
     |  implicit def synch(x: String)=x.toInt+20
     | def f1(s: String):Int=s
     | }
我正在做的是:

我隐含地将String转换为int并将20添加到该数字,因此我通过使用synch作为参数并使用implicit来定义一个string方法。之后,将值转换为int并向其添加20

在下一个方法中,如果arugment为string且返回类型为Int,那么它将隐含地调用该synch方法

scala> val aty=new c
aty: c = c@1f4da09

scala> aty.f1("50")
res10: Int = 70