我通常通过LiftWeb中的Loggable包装器将Scala与SLF4J一起使用。除了仅由 1表达式链构成的非常常见的方法外,这种方法效果很好。
因此,如果您想将记录添加到这样的方法,那么简单漂亮,没有大括号
def method1():Z = a.doX(x).doY(y).doZ()
必须成为:
def method1():Z = {
val v = a.doX(x).doY(y).doZ()
logger.info("the value is %s".format(v))
v
}
不太一样,是吗?我试着用它来解决它:
class ChainableLoggable[T](val v:T){
def logInfo(logger:Logger, msg:String, other:Any*):T = {
logger.info(msg.format(v, other))
v
}
}
implicit def anyToChainableLogger[T](v:T):ChainableLoggable[T] = new ChainableLoggable(v)
现在我可以使用更简单的表格
def method1():Z = a.doX(x).doY(y).doZ() logInfo(logger, "the value is %s")
然而,1个额外的对象实例化和来自Any的隐式开始看起来像代码发臭。
有谁知道更好的解决方案?或许我甚至不应该为此烦恼?
答案 0 :(得分:2)
这看起来是正确的方法,特别是如果你没有隐含的抽头(不在标准库中,但是这样的东西被广泛使用 - 并且tap
是标准的红宝石):
class TapAnything[A](a: A) {
def tap(f: A => Any): A = { f(a); a }
}
implicit def anything_can_be_tapped[A](a: A) = new TapAnything(a)
有了这个,将信息隐含在自己的内容就不那么重要了,但如果你使用它,那就是对
的改进了。.tap(v => logger.info("the value is %s".format(v)))
答案 1 :(得分:2)
Scala 2.10只为您提供了一个解决方案 - 这是一个新功能Value Class,它允许您获得与隐式包装器提供的相同的效果,但没有来自实例化这些包装类的开销。要应用它,您必须像这样重写代码:
implicit class ChainableLoggable[T](val v : T) extends AnyVal {
def logInfo(logger:Logger, msg:String, other:Any*) : T = {
logger.info(msg.format(v, other))
v
}
}
编译器会将logInfo
转换为Java的常用“util”静态方法的类比,方法是将v : T
添加到它的参数列表中并相应地更新它的用法 - 看,没有任何实例化。
答案 2 :(得分:0)
如果您想避免使用implicits,可以在自己的日志记录特征中定义类似这样的函数。可能不如带有隐含的解决方案那么漂亮。
def info[A](a:A)(message:A=>String) = {
logger.info(message(a))
a
}
info(a.doX(x).doY(y).doZ())("the value is " + _)