我有一些测试结果,我无法解释。
第一个测试在包含4个元素的列表上执行过滤,map和reduce:
{
val counter = new AtomicInteger(0)
val l = List(1, 2, 3, 4)
val filtered = l.filter{ i =>
counter.incrementAndGet()
true
}
val mapped = filtered.map{ i =>
counter.incrementAndGet()
i*2
}
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(11 == counter.get)
}
计数器按我的预期递增11次:过滤期间每个元素一次,映射期间每个元素一次,三次加起来元素。
使用通配符会导致结果发生变化:
{
val counter = new AtomicInteger(0)
val l = List(1, 2, 3, 4)
val filtered = l.filter{
counter.incrementAndGet()
_ > 0
}
val mapped = filtered.map{
counter.incrementAndGet()
_*2
}
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(5 == counter.get)
}
我无法弄清楚如何在reduce中使用通配符(代码没有编译),但是现在,计数器只增加了5倍!!
所以,问题#1:为什么通配符会改变调用计数器的次数以及它是如何工作的?
然后是我的第二个相关问题。我对视图的理解是他们会懒惰地执行传递给monadic方法的函数,但是下面的代码没有显示出来。
{
val counter = new AtomicInteger(0)
val l = Seq(1, 2, 3, 4).view
val filtered = l.filter{
counter.incrementAndGet()
_ > 0
}
println("after filter: " + counter.get)
val mapped = filtered.map{
counter.incrementAndGet()
_*2
}
println("after map: " + counter.get)
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("after reduce: " + counter.get)
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(5 == counter.get)
}
输出结果为:
after filter: 1
after map: 2
after reduce: 5
counted 5 and result is 20
问题2:为什么函数会立即执行?
我正在使用Scala 2.10
答案 0 :(得分:11)
你可能在想那个
filter {
println
_ > 0
}
装置
filter{ i =>
println
i > 0
}
但Scala有其他想法。原因是
{ println; _ > 0 }
是首先打印内容的语句,然后返回> 0
函数。因此,它将您正在做的事情解释为指定函数的有趣方式,相当于:
val p = { println; (i: Int) => i > 0 }
filter(p)
反过来相当于
println
val temp = (i: Int) => i > 0 // Temporary name, forget we did this!
val p = temp
filter(p)
你可以想象的并不是你想要的方式 - 你只在开始时打印(或者在你的情况下做增量)。你的问题都源于此。
确保您使用下划线表示“填写参数”,表示您只有一个表达式!如果您使用多个语句,最好坚持使用明确命名的参数。