我一直在探索仿函数,我在理解forEach
仿函数在幕后所做的事情时遇到了一些麻烦。例如,当我将其输入游乐场时:
let array = [1] // [1]
array.forEach { $0.value } // (3 times)
array.forEach { _ in print("hello") } // (2 times)
当我展开(3 times)
或(2 times)
时,它只显示()
首先,为什么1个元素的数组上有多个执行,为什么两个forEach
计算的执行次数不同?
答案 0 :(得分:3)
这是一个令人困惑的情况。
让我们先考虑第二个forEach
:
array.forEach { _ in print("hello") } // (2 times)
该行的不同部分在不同时间执行,Swift将每个时间作为单独的执行进行计数。第一次是它调用array.forEach
时,第二次是在forEach
调用时,它在匿名函数体内执行对print
的调用。如果我们输入换行符,我们可以看到Swift只执行一行并报告其“值”:
array.forEach { _ in // [1]
print("hello") // ()
}
我们也可以尝试将匿名函数放在变量中:
let p: (Int) -> () = { _ in print("hello") } // (2 times)
array.forEach(p) // [1]
在上面,Swift执行一次let p
行的一部分来创建匿名函数并将其存储在p
中,然后该行的另一部分将在print
内部调用print
功能。
Swift报告()
行的值为forEach
,因为()
的参数必须是返回Void
的函数(空元组,即{{1} }})。由于print
已经返回()
,因此Swift只允许它为该行的值。
在我们回过头来考虑您的第一个forEach
示例之前,让我们再考虑另一个例子:
print("hello"); print("goodbye") // (2 times)
Swift说这行执行了两次,因为该行上的每个单独的语句都算作一个单独的执行。
现在让我们考虑你的第一个例子:
array.forEach { $0.value } // (3 times)
让我们尝试使用换行符:
array.forEach { // [1]
$0.value // (2 times)
}
好的,所以forEach
调用本身算作一次执行,如预期的那样。但Swift声称它正在执行两次匿名函数的主体。为什么呢?
回想一下forEach
的参数必须是返回()
的函数。但$0.value
的类型不是()
;它是内部类型Builtin.Int64
。因此,Swift在该行的末尾插入另一个语句,以返回()
。实际上,Swift就像你写的那样:
array.forEach { // [1]
$0.value; () // (2 times)
}
我们可以通过在函数中明确添加另一行来证明:
array.forEach { // [1]
$0.value // <<<opaque type>>>
()
}
现在Swift认为每一行都按预期执行一次。
答案 1 :(得分:1)
您在Swift playground的右栏中看到的不是此特定行的执行次数,而是此行中的语句数量给出了可在此列中显示的结果。
array.forEach { $0.value }
提供(3 times)
因为它会解析为三个结果:第一个用于array
,第二个用于$0.value
。
将此行更改为:
array.forEach { \\ [1]
$0 \\ (2 times)
}
$0
给出了两个结果。第一个结果是通过评估$0
给出的,第二个是通过评估隐式return ()
语句给出的。让我们明确一点:
array.forEach { // [1]
$0 // 1
return () // ()
}
当您展开(N times)
结果时,playground应该显示此行中所有语句的结果,但它会使用错误执行此操作。有时它显示所有结果或仅显示最后结果或仅显示第一个结果或没有结果。我不知道为什么。