如何在'for'理解中添加跟踪?

时间:2010-02-24 00:12:02

标签: logging scala

对于for理解中的日志跟踪,我使用了这样的虚拟赋值:

val ll = List(List(1,2),List(1))            

for {
  outer <- ll 
  a = Console.println(outer)   // Dummy assignment makes it compile
  inner <- outer
} yield inner

a =位似乎很尴尬。有更清洁的方式吗?

5 个答案:

答案 0 :(得分:71)

答案 1 :(得分:21)

您可以随时定义自己的trace功能:

def trace[T](x: T) = {
  println(x) // or your favourite logging framework :)
  x
}

那么for comprehension看起来像:

for { 
  outer <- ll
  inner <- trace(outer)
} yield inner

或者,如果您想要打印更多信息,可以按如下方式定义trace

def trace[T](message: String, x: T) = {
  println(message)
  x
}

和for comprehension看起来像:

for { 
  outer <- ll
  inner <- trace("Value: " + outer, outer)
} yield inner

编辑:在回复您的评论时,是的,您可以写trace,使其在目标右侧发挥作用!你只需要使用一些隐含的技巧。实际上,它确实看起来比应用于左边时更好:)。

为此,您必须首先定义一个Traceable的类,然后定义到该类的隐式转换:

class Traceable[A](x: A) { 
  def traced = {
    println(x)
    x
  }
}

implicit def any2Traceable[A](x: A) = new Traceable(x)

然后,您在提供的代码中唯一需要修改的是将traced添加到要跟踪的值的末尾。例如:

for { 
  outer <- ll
  inner <- outer traced
} yield inner

(这由Scala编译器翻译成outer.traced

答案 2 :(得分:15)

无论价值多少,由于作业是假的,您可以将a替换为_

for { 
  outer <- ll  // ; // semi-colon needed on Scala 2.7
  _ = Console.println(outer)   // dummy assignment makes it compile 
  inner <- outer 
} yield inner 

答案 3 :(得分:1)

Flaviu的回答激发了我尝试使用暗示。我们的想法是通过线上右侧的“跟踪”来查看跟踪是否更好:

import Trace._

object Main {  
  def main(args:Array[String])  {
    val listList = List(List(1,2,3), List(3,4))    
    for {
      list <- trace1(listList, "lList is: %s", listList)  // trace() 
      item <- list traced("list is: %s", list)            // implicit         
    } yield item

我也想尝试在错误记录中混合相同的理解。错误记录看起来最好与Daniel的方法相结合:

    val optOpt:Option[Option[Int]] = Some(Some(1))
    for {
      opt <- optOpt;
      _ = trace2("opt found: %s", opt)   // trying Daniel's suggestion
      int <- opt orElse 
        err("num not found in: %s", opt)   // together with error logging
    } yield int
  }
}

以下是两个实验的支持代码:

object Trace {
  def trace1[T](any:T, message:String, params:AnyRef*):T = {
    Console println String.format("TRA: " + message, params:_*)
    any
  }

  def trace2[T](message:String, params:AnyRef*) {
    Console println String.format("TRA: " + message, params:_*)
  }

  def err[T](message:String, params:AnyRef*):Option[T] = {
    Console println String.format("ERR: " + message, params:_*)
    None
  }

  implicit def anyRefToTraceable[T](anyRef:T):Traceable[T] = {
    new Traceable(anyRef)
  }

  class Traceable[T](val self:T) {
    def traced(message:String, params:AnyRef*):T = {
      Console println String.format("TRA: " + message, params:_*)
      self
    }  
  }  
}

答案 4 :(得分:0)

Scala 2.13开始,即链接操作tap已包含在标准库中,可以在需要打印管道的某些中间状态的地方以最小的介入使用:

import util.chaining._

// val lists = List(List(1, 2), List(1))
for {
  outer <- lists
  inner <- outer.tap(println)
} yield inner
// List(2, 4, 6)
// List(4, 8, 12)
// ls: List[Int] = List(4, 8, 12)

tap链接操作对值(在这种情况下为println列表)施加副作用(在这种情况下为outer),同时返回未更改的值:

  

def tap [U](f:(A)=> U):A