3

我通常通过 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 的隐式实例化开始看起来像代码臭。

有谁知道更好的解决方案?或者也许我什至不应该为此烦恼?

4

3 回答 3

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

于 2012-08-07T08:11:39.770 回答
2

这看起来是正确的方法,特别是如果你没有隐含的水龙头(不在标准库中,但这样的东西被相当广泛地使用——并且tap在 Ruby 中是标准的):

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)))
于 2012-08-06T21:29:04.387 回答
0

如果你想避免使用隐式,你可以在你自己的日志特性中定义像这样的函数。虽然可能不如隐含的解决方案漂亮。

def info[A](a:A)(message:A=>String) = {
  logger.info(message(a))
  a
}

info(a.doX(x).doY(y).doZ())("the value is " + _)
于 2012-08-06T21:41:49.360 回答