使用Scala集合时出现奇怪的结果

Joh*_*ith 1 scala scala-collections

我有一些测试结果,我无法解释.

第一个测试在包含4个元素的列表上执行过滤,映射和缩小:

{
    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)
}
Run Code Online (Sandbox Code Playgroud)

计数器按我的预期递增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)
}
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何在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)
}
Run Code Online (Sandbox Code Playgroud)

输出是:

after filter: 1
after map: 2
after reduce: 5
counted 5 and result is 20
Run Code Online (Sandbox Code Playgroud)

问题2:为什么函数会立即执行?

我正在使用Scala 2.10

Rex*_*err 11

你可能在想

filter {
  println
  _ > 0
}
Run Code Online (Sandbox Code Playgroud)

手段

filter{ i =>
  println
  i > 0
}
Run Code Online (Sandbox Code Playgroud)

但斯卡拉有其他想法.原因是

{ println; _ > 0 }
Run Code Online (Sandbox Code Playgroud)

是一个首先打印东西,然后返回该> 0函数的语句.所以它将你正在做的事情解释为一种指定函数的有趣方式,相当于:

val p = { println; (i: Int) => i > 0 }
filter(p)
Run Code Online (Sandbox Code Playgroud)

而这相当于

println
val temp = (i: Int) => i > 0   // Temporary name, forget we did this!
val p = temp
filter(p)
Run Code Online (Sandbox Code Playgroud)

你可以想象的并不是你想要的方式 - 你只在开始时打印(或者在你的情况下做增量).你的问题都源于此.

确保您使用下划线表示"填写参数",表示您只有一个表达式!如果您使用多个语句,最好坚持使用明确命名的参数.