scala - 登录Scala时如何保持返回值

标签 scala logging

在Java中进行编程时,我总是记录输入参数和方法的返回值,但是在scala中,方法的最后一行是返回值。所以我必须做类似的事情:

def myFunc() = {
  val rs = calcSomeResult()
  logger.info("result is:" + rs)
  rs
}

为了简单起见,我编写了一个实用程序:
class LogUtil(val f: (String) => Unit) {
 def logWithValue[T](msg: String, value: T): T = { f(msg); value }
}

object LogUtil {
  def withValue[T](f: String => Unit): ((String, T) => T) = new LogUtil(f).logWithValue _
}

然后我将其用作:
val rs = calcSomeResult()
withValue(logger.info)("result is:" + rs, rs) 

它将记录该值并返回它。它对我有用,但似乎很奇怪。因为我是一个古老的Java程序员,但是对Scala还是陌生的,所以我不知道在Scala中是否有更惯用的方法来做到这一点。

感谢您的帮助,现在我使用romusz推荐的Kestrel组合器创建一个更好的工具
object LogUtil {
  def kestrel[A](x: A)(f: A => Unit): A = { f(x); x }
  def logV[A](f: String => Unit)(s: String, x: A) = kestrel(x) { y => f(s + ": " + y)}
}

我添加了f参数,以便可以通过slf4j将它传递给记录器,并且测试用例为:
class LogUtilSpec extends FlatSpec with ShouldMatchers {
  val logger = LoggerFactory.getLogger(this.getClass())
  import LogUtil._

"LogUtil" should "print log info and keep the value, and the calc for value should only be called once" in {
  def calcValue = { println("calcValue"); 100 } // to confirm it's called only once 
  val v = logV(logger.info)("result is", calcValue)
  v should be === 100
  }
}

最佳答案

您正在寻找的被称为Kestrel组合器(K combinator):Kxy = x。在返回传递给它的值时,您可以执行各种副作用操作(不仅是日志记录)。阅读https://github.com/raganwald/homoiconic/blob/master/2008-10-29/kestrel.markdown#readme

在Scala中,最简单的实现方法是:

  def kestrel[A](x: A)(f: A => Unit): A = { f(x); x }

然后,您可以将打印/记录功能定义为:
def logging[A](x: A) = kestrel(x)(println)
def logging[A](s: String, x: A) = kestrel(x){ y => println(s + ": " + y) }

并像这样使用它:
logging(1 + 2) + logging(3 + 4)

您的示例函数变成了单行代码:
def myFunc() = logging("result is", calcSomeResult())

如果您更喜欢OO表示法,则可以使用其他答案中所示的隐式表示法,但是这种方法的问题在于,每次要记录某些内容时,您都将创建一个新对象,如果经常这样做,可能会导致性能下降。但是为了完整起见,它看起来像这样:
implicit def anyToLogging[A](a: A) = new {
  def log = logging(a)
  def log(msg: String) = logging(msg, a)
}

像这样使用它:
def myFunc() = calcSomeResult().log("result is")

关于scala - 登录Scala时如何保持返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9671620/

相关文章:

java - 记录 jax-ws http 请求和响应

scala - 两个自然数不相等的证据?

scala - build.sbt 和 build.scala 有什么区别?

Scala 和 Akka - 使用 Akka Testkit 将 actor 作为系统进行测试

scala - 如何在 playframework 2 上创建仅测试路线和 View ?

scala - 当生成的存在类型太复杂时,toList on shapeless HList 失败

Spring Boot jetty/tomcat 内嵌访问日志配置

python - 谷歌应用引擎日志记录系统中的无限递归

python - 捕获 SysLogHandler 的输出

android - 将日志输出重定向到客户手机上的 SD 卡