gpt4 book ai didi

Swift @autoclosure 参数包装提供显式关闭

转载 作者:行者123 更新时间:2023-11-28 06:08:44 24 4
gpt4 key购买 nike

考虑以下函数:

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 '()'?

这是故意的吗?阅读 @autoclosure 的文档我没有找到关于参数是否总是包装的声明,即使在提供闭包时也是如此。我对@autoclosure的理解是:
采用闭包参数。如果参数不是闭包但与闭包返回的类型相同,则将其包装。
但是,我看到的行为是:不管怎样都包装参数。

一个更详细的例子让我觉得这很奇怪:

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"

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

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类型为 () -> T .提供给init(key: String, defaultValue: () -> T) ,在我的期望中应该可以正常工作,因为参数和参数具有相同的类型(而参数是 @autoclosure )。
但是,Swift 似乎包装了提供的闭包,有效地创建了 () -> () -> T , 它创建 Setting<() -> T>而不是 Setting<T> .

我可以通过声明 init 来解决这个问题这需要一个明确的非 @autoclosure参数:

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

真正令人生畏的是我可以简单地转发到 init服用@autoclosure参数并且有效。

我在这里遗漏了什么,还是 Swift 的设计不可能为 @autoclosure 提供闭包参数?参数?

最佳答案

Swift 期望您将产生 Int 的表达式传递给 whatever(foo:),Swift 会将该表达式包装在类型为 ( ) -> 整数

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

当你这样调用它时:

func whatever(foo: {5})

您正在传递一个导致 () -> Int 而不是 Swift 期望的 Int 的表达式。这就是为什么它建议您添加 () 并调用该闭包以获得返回 Int 的表达式:

func whatever(foo: {5}())

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

您可以通过在 Playground 中运行来验证这一点:

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

如果您希望 whatever(foo: 也能够采用 () -> Int 闭包,请重载它并在调用 之后调用自动闭包版本富:

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

关于Swift @autoclosure 参数包装提供显式关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47366660/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com