对于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 =
位似乎很尴尬。有更清洁的方式吗?
答案 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