Swift Playground 显示错误的语句执行次数(数组上的 forEach)

Posted

技术标签:

【中文标题】Swift Playground 显示错误的语句执行次数(数组上的 forEach)【英文标题】:Swift playground shows wrong number of executions for statement (forEach on array) 【发布时间】:2015-10-29 19:13:21 【问题描述】:

我一直在探索函子,但在理解 forEach 函子在幕后所做的事情时遇到了一些麻烦。例如,当我将其输入到游乐场时:

let array = [1] // [1]
array.forEach  $0.value  // (3 times)
array.forEach  _ in print("hello")  // (2 times)

当我展开 (3 times)(2 times) 时,它只会显示 ()

首先,为什么在一个包含 1 个元素的数组上执行多次,以及为什么两次 forEach 计算的执行次数不同?

【问题讨论】:

forEach() 对每个数组元素只调用一次闭包。如果 Playground 指示其他内容,则它是 Playground 中的错误。如有疑问,请使用已编译的项目并添加调试输出或设置断点。 【参考方案1】:

这是一个相当混乱的情况。

让我们首先考虑第二个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

Swift 报告print 行的值是(),因为forEachs 参数必须是返回()(空元组,又名Void)的函数。由于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 认为每一行都按预期执行一次。

【讨论】:

【参考方案2】:

您在 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 应该会向您显示这一行中所有语句的结果,但这样做是有错误的。有时它会显示所有结果或仅显示最后一个结果或仅显示第一个结果或没有结果。我不知道为什么。

【讨论】:

以上是关于Swift Playground 显示错误的语句执行次数(数组上的 forEach)的主要内容,如果未能解决你的问题,请参考以下文章

swift3 Playground 未能获得路径的沙盒扩展

在 Swift/Playground 中使用 .append 选项到数组结束时出现错误

Swift 泛型控制台输出

Swift Playground WebView 不会显示本地图像

在 Swift Playground 中创建 UIManagedDocument - 信号 SIGABRT 错误

Swift 2 Xcode 7.2.1 Playground 错误 - 文件“日志”无法保存在文件夹“库”中