1

クラスの他のメソッドが呼び出されるたびに常に呼び出されるプライベートメンテナンスメソッドsynchを定義するクラスがあります。もちろん、これを行う古典的な方法は次のとおりです。

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

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

ただし、上記のように明示的に呼び出す必要がないように、これを暗黙的に実行する方法はありますか?

編集:

これが可能であれば、同期メソッドを他の各メソッドのまたはに呼び出すかどうかを定義することもできますか?

4

3 に答える 3

3

次のように使用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
}

quasiquote にはコンパイラ プラグインを使用する必要があります。メソッドの前に呼び出したい場合は、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")
                           ^
于 2013-11-14T07:38:20.230 に答える
0

暗黙的な定義は、型エラーを修正するためにコンパイラがプログラムに挿入できる定義です。たとえば、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キーワードを使用し、その後値を変換して追加する 1 つのメソッドを定義しました。implicitstringint20

次のメソッドの場合、引数が is でstringあり、戻り値の型が is であるIntため、暗黙的にその同期メソッドを呼び出します

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

scala> aty.f1("50")
res10: Int = 70
于 2013-11-14T07:26:58.457 に答える
0

バイトコードの書き換え、またはマクロ注釈でそれを行うことができます。どちらもかなり複雑になります。考慮すべき事項:

  1. 継承されたメソッドにもこれが発生することを望みますか?

  2. このsynchクラスの他のメソッドを呼び出すと、無限ループが発生します。

于 2013-11-14T07:13:10.970 に答える