当前位置: 首页 > 知识库问答 >
问题:

Swift@自动闭包参数包装提供了显式闭包

封烈
2023-03-14

考虑以下功能

func whatever(foo: @autoclosure () -> Int) {
  let x = foo()
  print(x)
}

当然,我们可以像这样调用它:

whatever(foo: 5)
// prints: 5

但是,提供显式闭包参数会导致编译器抱怨:

whatever(foo: { 5 })
// Error: Function produces expected type 'Int'; did you mean to call it with '()'?

这是您的意图吗?阅读@自动闭包的留档时,我没有找到关于参数是否始终被包装的语句,即使在提供闭包时也是如此。我对@自动闭包的理解是:
接受闭包参数。如果参数不是闭包,但与闭包返回的类型相同,则包装它。
然而,我看到的行为是:无论如何都要包装参数。

一个更详细的例子使这在我看来很奇怪:

struct Defaults {

  static var dispatcher: Defaults = ...

  subscript<T>(setting: Setting<T>) -> T { ... }

  struct Setting<T> {
    let key: String
    let defaultValue: () -> T

    init(key: String, defaultValue: @escaping @autoclosure () -> T) {
      self.key = key
      self.defaultValue = defaultValue
    }
  }
}

extension Defaults.Setting {
  static var nickname: Defaults.Setting<String> {
    return Defaults.Setting(key: "__nickname", defaultValue: "Angela Merkel")
  }
}

//  Usage:
Defaults.dispatcher[.nickname] = "Emmanuel Macron"

现在假设我想散列设置值的键:

extension Defaults.Setting {
  var withHashedKey: Defaults.Setting<T> {
    return Defaults.Setting(key: key.md5(), defaultValue: defaultValue)
    // Error: Cannot convert return expression of type 'Defaults.Setting<() -> T>' to return type 'Defaults.Setting<T>'
  }
}

为了澄清:defaultValue的类型是()-

extension Defaults.Setting {
  init(key: String, defaultValue: @escaping () -> T) {
    self.init(key: key, defaultValue: defaultValue)
  }
}

真正令人望而生畏的是,我可以简单地使用< code>@autoclosure参数转发到< code>init,它就工作了。< br>
是我遗漏了什么,还是Swift的设计无法为< code>@autoclosure参数提供闭包变量?

共有1个答案

微生新霁
2023-03-14

Swift 期望您将一个生成 Int 的表达式传递给 whatever(foo:),Swift 会将该表达式包装在类型 () 的闭包中 -

func whatever(foo: @autoclosure () -> Int) {
    let x = foo()
    print(x)
}

当你这样称呼它:

func whatever(foo: {5})

您传递的表达式将导致()-

func whatever(foo: {5}())

请注意,由于 Swift 将 {5}() 包装在闭包中,因此在调用 whatever(foo:) 之前不会对其进行评估,但实际上调用会延迟,直到您评估 let x = foo()。

你可以通过在操场上运行来验证这一点:

func whatever(foo: @autoclosure () -> Int) {
    print("inside whatever")
    let x = foo()
    print(x)
    let y = foo()
    print(y)
}

whatever(foo: { print("hi"); return 3 }())

输出:

inside whatever
hi
3
hi
3

如果你想要任何东西(foo:也可以取一个()-

func whatever(foo: @autoclosure () -> Int) {
    print("autoclosure whatever")
    let x = foo()
    print(x)
}

func whatever(foo: () -> Int) {
    print("closure whatever")
    whatever(foo: foo())

}

whatever(foo: { print("two"); return 6 })
whatever(foo: { print("two"); return 6 }())

输出:

closure whatever
autoclosure whatever
two
6
autoclosure whatever
two
6

 类似资料:
  • 闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 匿名函数比较相似。 全局函数和嵌套函数其实就是特殊的闭包。 闭包的形式有: 全局函数 嵌套函数 闭包表达式 有名字但不能捕获任何值。 有名字,也能捕获封闭函数内的值。 无名闭包,使用轻量级语法,可以根据上下

  • 主要内容:以下是纠正/补充内容:Swift 4中的Closures(闭包)类似于组织为块的自包含函数,并且像C和Objective C语言一样调用。 在函数内定义的常量和变量引用被捕获并存储在闭包中。 函数可以看作是闭包的特殊情况,它采用以下三种形式 - 全局函数 嵌套函数 闭包表达式 有名称,不捕获任何值 有名称,从封闭函数中捕获值。 未命名的闭包从相邻块中捕获值 Swift 4语言中的Closures(闭包)表达式遵循清晰,

  • 问题内容: 鉴于: 有什么方法可以使参数(和)的类型也保持不变? 更改类型会出现以下错误: @escaping属性仅适用于函数类型 删除该属性后,代码将编译并运行,但由于闭包使函数的作用范围变大,因此似乎并不正确。 问题答案: 有一个SR-2552报告无法识别功能类型别名。这就是错误的原因。您可以通过扩展函数签名中的函数类型来解决: 编辑1 : 我实际上是在xcode 8 beta版本下,但尚未解

  • 闭包作为参数(Taking closures as arguments) 现在我们知道了闭包是 trait,我们已经知道了如何接受和返回闭包;就像任何其它的 trait! 这也意味着我们也可以选择静态或动态分发。首先,让我们写一个获取可调用结构的函数,调用它,然后返回结果: fn call_with_one<F>(some_closure: F) -> i32 where F : Fn(i

  • 问题内容: 目前,我正在执行在循环内执行闭包的代码。我想知道所有闭包何时完成执行。目前,我正在使用一个计数器,并在关闭完成时将其递增,然后将其与要执行的时间进行比较。代码如下 有没有计数器的更好的方法。谢谢。 问题答案: 您可以为此使用。它的工作就像计数信号灯一样。您可以通过调用来增加计数,并通过来减少计数。您可以使用以下命令安排闭包在计数达到0时执行:

  • 问题内容: 我正在尝试将项目更新为Swift 3.0,但遇到了一些困难。我收到下一个错误:“转义的闭包只能按值显式捕获inout参数”。 问题出在此函数内部: 有人可以帮我解决这个问题吗? 问题答案: 仅将参数用于异步任务是一种滥用–就像在调用函数时一样,传递给参数的调用者的值不会更改。 这是因为它不是传递引用,它只是参数的可变影子副本,该副本在函数退出时写回到调用方–并且由于异步函数立即退出,因