考虑以下功能:
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
参数提供闭包参数?
答案 0 :(得分:1)
Swift希望您传递一个导致SELECT l.id_member,
m.usertitle
FROM smf_user_points_log l
INNER JOIN smf_members m
ON m.id_member=l.id_member
WHERE l.id_school_year in (SELECT id_school_year FROM smf_settings)
AND l.points >= 50
AND m.date_registered < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
到Int
的表达式,Swift会将该表达式包装在whatever(foo:)
类型的闭包中。
() -> Int
当你这样称呼时:
func whatever(foo: @autoclosure () -> Int) {
let x = foo()
print(x)
}
您传递的表达式导致func whatever(foo: {5})
而不是() -> Int
Swift期望。这就是为什么它建议你添加Int
并调用该闭包来获得一个返回()
的表达式:
Int
请注意,由于Swift将func whatever(foo: {5}())
包装在一个闭包中,因此在调用{5}()
之前不会对其进行评估,但事实上,在您评估whatever(foo:)
之前,调用会延迟。
您可以在Playground中运行此功能来验证这一点:
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
能够进行whatever(foo:
关闭,请在调用() -> Int
后重载并调用autoclosure版本:
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 }())