- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑以下函数:
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/
我是一名优秀的程序员,十分优秀!