如何隐式调用方法时调用其他方法?(How to implicitly invoke a method

2019-10-19 00:18发布

我只要调用类的任何其他方法总是被调用它定义了一个私人维修方法同步 ,这是我想要的类。 这样做当然会成为经典的方法:

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

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

但是,有没有办法让这个隐含完成的,所以我不必调用它明确地像我这样做以上?

编辑:

如果能够做到这一点,是不是也可以定义,如果我想以后还是互相方法之前 ,被称为同步方法?

Answer 1:

你可以通过创建自定义的包装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
}

你必须使用一个编译器插件为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")
                           ^


Answer 2:

你可以用字节码重写做到这一点,或者用宏注释 。 双方将是相当复杂的。 有些事情要考虑:

  1. 你是否也想做到这一点,以继承的方法?

  2. 如果synch调用这个类的任何其他方法,你会得到一个无限循环。



Answer 3:

隐式的定义是那些编译器允许插入一个方案,以解决任何类型的错误。 例如,如果X + Y不类型检查,则编译器可能会改变它来转换(x)+ y,其中转换是一些可用的隐式转换。 如果转换变化x转换成的东西,有一个+方法的,那么它的类型检查和正常运行这种变化可能会解决的程序。 如果真的转换只是一个简单的转换功能,然后离开它的源代码可以是一个澄清。

基本上implicit用于隐式转换,所以我尝试了用一个例子,我认为这将帮助你:

scala> class c{
     |  implicit def synch(x: String)=x.toInt+20
     | def f1(s: String):Int=s
     | }

我在做什么是:

我正在通话隐含字符串int和加入20到该号码所以,我所定义的一个方法,该方法是synch使用关键字implicit ,将采取string作为参数和转换值后int和添加20到它。

在接下来的方法,如果arugment是string ,并将其返回类型为Int所以它会隐含调用同步方法

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

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


文章来源: How to implicitly invoke a method when other methods are invoked?
标签: scala