2013-11-14 2 views
1

У меня есть класс, который определяет частный метод обслуживания synch, который я всегда должен вызывать всякий раз, когда вызывается какой-либо другой метод класса. Классический способ сделать это, конечно, будет:Как неявно вызывать метод при вызове других методов?

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

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

Однако, есть ли способ, чтобы это делалось неявно, так что я не должен вызывать его явно, как я выше?

EDIT:

Если можно это сделать, это также можно определить, если я хочу, чтобы синхронизирующий метод можно назвать после или перед друг с другом методом?

ответ

0

Вы можете сделать это с помощью перезаписи байтового кода или с помощью macro annotations. Оба были бы довольно сложными. Некоторые вещи, которые следует учитывать:

  1. Вы также хотите, чтобы это произошло с унаследованными методами?

  2. Если synch вызывает любые другие методы этого класса, вы получите бесконечный цикл.

+0

Спасибо за ответ Алексей! В моем случае было бы достаточно, если бы он работал на простой основе для каждого класса, поэтому нет необходимости рассматривать унаследованный метод. Синхронизация не вызывает других методов, она просто проверяет и обновляет значения некоторых частных переменных-членов. – csvan

+0

@chrsva: См. [Этот ответ] (http://stackoverflow.com/a/19977114/406435) для примера макрокоманд. – senia

0

Неявные определения являются те, что компилятор имеет право включить в программу для того, чтобы исправить какие-либо из своих ошибок типа. Например, если x + y не устанавливает проверку, то компилятор может изменить его для преобразования (x) + y, где convert - это некоторое доступное неявное преобразование. Если преобразовать изменения x в то, что имеет метод +, то это изменение может исправить программу, чтобы она корректно проверяла и запускала. Если преобразование действительно является просто простой функцией преобразования, то отказ от исходного кода может быть уточнением.

В основном implicit используется для преобразования неявно, так что я попробовал с помощью примера я думаю, что это поможет вам:

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

, что я делаю это:

я неявным беседуя строку в целое и добавив 20 к этому числу, поэтому для этого я определил один метод, который равен synch, используя ключевое слово implicit, которое примет в качестве аргумента string, после чего преобразует значение в int и добавляет к нему 20.

в следующем методе, если arugment является string и возвращать тип Int так будет неявным вызовом, который SYNCH методы

scala> val aty=new c 
aty: c = [email protected] 

scala> aty.f1("50") 
res10: Int = 70 
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 
} 

Для квазиквадратов вам необходимо использовать compiler plugin. Если вы хотите позвонить 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") 
         ^
Смежные вопросы