11

例外をスローできるコードを、例外をログに記録して続行する try-catch ブロックでラップするとします。何かのようなもの:

loggingExceptions {
  // something dangerous
}

理想的には、呼び出し元のオブジェクトで定義されている Logger があれば、それをログに記録するために使用したいと思います (存在しない場合は、コンパイル時にエラーが発生します)。次のように定義したいと思います。

def loggingExceptions[L <: { def logger: Logger }](work: => Unit)(implicit objectWithLogger: L): Unit = {
  try {
    work
  } catch {
    case t: Exception => objectWithLogger.logger.error(t.getMessage)
  }
}

objectWithLogger は、クライアント コードで「魔法のように」「this」に展開されます。これ(または同様のこと)は可能ですか?

4

3 に答える 3

14

実際、それはあなたが望むように行うことができます。他の回答者はあまりにも早く降伏しました。白旗なし!

package object foo {
  type HasLogger = { def logger: Logger }
  implicit def mkLog(x: HasLogger) = new {
    def loggingExceptions(body: => Unit): Unit =
      try body
      catch { case ex: Exception => println(ex) }
  }
}

package foo {
  case class Logger(name: String) { }

  // Doesn't compile:
  // class A {
  //   def f = this.loggingExceptions(println("hi"))
  // }
  // 1124.scala:14: error: value loggingExceptions is not a member of foo.A
  //         def f = this.loggingExceptions(println("hi"))
  //                      ^
  // one error found  

  // Does compile
  class B {
    def logger = Logger("B")
    def f = this.loggingExceptions(println("hi"))
    def g = this.loggingExceptions(throw new Exception)
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    val b = new foo.B
    b.f
    b.g
  }
}

// output
//
// % scala Test
// hi
// java.lang.Exception
于 2010-11-24T20:35:33.520 に答える
4

Debilskiの答えは機能しますが、ここで構造型(つまり)を使用する正当な理由があるかどうかはわかりません{ def logger: Logger }logger構造型の実装はリフレクションに依存しているため、これを行うと、 が呼び出されるたびに余分なランタイム オーバーヘッドが発生します。このloggingExceptionsメソッドはロギングと密接に結びついているため、ロギング トレイトの一部にします。

trait Logging {
   def logger: Logger

   final def loggingExceptions(body: => Unit) =
      try body catch { case e: Exception => logger.error(e.getMessage) }
}

trait ConcreteLogging extends Logging { 
   val logger = // ...
}

object MyObject extends SomeClass with ConcreteLogging {
   def main {
      // ...
      loggingExceptions { 
         // ...
      }
   }
}
于 2010-11-24T19:35:24.963 に答える
3

使用したいすべてのクラスにトレイトをdef loggingExceptions追加し、このトレイトに使用可能であることを期待するセルフタイプを追加def logger: Loggerできます。

trait LoggingExceptions {
    this: { def logger: Logger } =>
  def loggingExceptions(work: => Unit) {
    try { work }
    catch { case t: Exception => logger.error(t.getMessage) }
  }
}

object MyObjectWithLogging extends OtherClass with LoggingExceptions {
  def logger: Logger = // ...

  def main {
    // ...
    loggingExceptions { // ...
    }
  }
}
于 2010-11-24T17:24:27.800 に答える