假设我想包装可以使用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”。这个(或类似的东西)可能吗?
答案 0 :(得分:11)
事实上,它可以按照您的意愿完成。其他的回答者投降得太快了。没有白旗!
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
答案 1 :(得分:4)
Debilski's answer会起作用,但我不确定我是否有充分的理由在这里使用结构类型(即{ 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 {
// ...
}
}
}
答案 2 :(得分: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 { // ...
}
}
}