我有一个类,它定义了一个私有维护方法synch,每当调用该类的任何其他方法时,我都希望始终调用它。这样做的经典方法当然是:
def method1 = {
synch
// ... do stuff
}
def method2 = {
synch
// ... do other stuff
}
但是,有什么方法可以隐式完成此操作,这样我就不必像上面那样显式调用它了?
编辑:
如果可以这样做,是否也可以定义我是否希望在其他方法之后或之前调用同步方法?
我有一个类,它定义了一个私有维护方法synch,每当调用该类的任何其他方法时,我都希望始终调用它。这样做的经典方法当然是:
def method1 = {
synch
// ... do stuff
}
def method2 = {
synch
// ... do other stuff
}
但是,有什么方法可以隐式完成此操作,这样我就不必像上面那样显式调用它了?
编辑:
如果可以这样做,是否也可以定义我是否希望在其他方法之后或之前调用同步方法?
您可以使用以下方式创建自定义包装def macros器Dynamic:
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
}
您必须为准引号使用编译器插件。如果你想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")
^
隐式定义是允许编译器插入到程序中以修复其任何类型错误的定义。例如,如果 x + y 不进行类型检查,则编译器可能会将其更改为 convert(x) + y,其中 convert 是一些可用的隐式转换。如果 convert 将 x 更改为具有 + 方法的内容,则此更改可能会修复程序,使其类型检查并正确运行。如果 convert 真的只是一个简单的转换函数,那么将其从源代码中删除可以澄清一下。
基本上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到它。
在下一个方法中,如果参数是string并且它返回类型是Int,那么它将隐式调用该同步方法
scala> val aty=new c
aty: c = c@1f4da09
scala> aty.f1("50")
res10: Int = 70
您可以通过字节码重写或宏注释来实现。两者都会相当复杂。需要考虑的一些事项:
您是否也希望这种情况发生在继承的方法上?
如果synch调用这个类的任何其他方法,你将得到一个无限循环。