Swift 为什么可以';我是否将某些表达式传递给标记为@conversion(block)的闭包参数?

Swift 为什么可以';我是否将某些表达式传递给标记为@conversion(block)的闭包参数?,swift,closures,Swift,Closures,我发现了这种奇怪的行为: 考虑以下代码: func foo(_ x: () -> Void) { } class Bar { func bar() { print("hello") } } var bar: Bar? = Bar() 这些文件汇编如下: foo(bar?.bar ?? {}) DispatchQueue.main.async(execute: (bar?.bar ?? {}) as () -> Void) 但这并不是: Di

我发现了这种奇怪的行为:

考虑以下代码:

func foo(_ x: () -> Void) {

}

class Bar {
    func bar() {
        print("hello")
    }
}

var bar: Bar? = Bar()
这些文件汇编如下:

foo(bar?.bar ?? {})
DispatchQueue.main.async(execute: (bar?.bar ?? {}) as () -> Void)
但这并不是:

DispatchQueue.main.async(execute: bar?.bar ?? {})
它会产生以下错误:

无法将类型“()->()”的值转换为预期的参数类型“@convention(block)(->Void”

现在,如果我将
bar
更改为:

func bar() -> (() -> Void)? {
    return { print("hello") }
}
然后做:

DispatchQueue.main.async(execute: bar() ?? {})
它编译

所以这肯定不是因为
操作符

问题:你能解释一下这种行为吗

低于这一点的一切都是我的实验


我发现
async
方法和
foo
之间的唯一区别是
execute
参数用
@约定(块)
标记

假设:我无法将可选链接表达式传递到标有
@convention(block)
的参数中

但这似乎是错误的,因为我可以这样做,但它仍然无法编译:

DispatchQueue.main.async(execute: Bar().bar ?? {})
看起来我还可以将表达式转换为
()->Void
,它神奇地编译:

foo(bar?.bar ?? {})
DispatchQueue.main.async(execute: (bar?.bar ?? {}) as () -> Void)
是不是
bar?.bar??{}
类型已为
()->Void
?这毫无意义

另一种编译方法是将
bar?.bar
提取为局部变量:

let barFunc = bar?.bar
DispatchQueue.main.async(execute: barFunc ?? {})

这就没什么意义了……

不是答案,但它可以引导你找到一些可能有用的东西:我和一个使用“SwiftLint”的大团队一起工作,出于某种原因,当我打算将某个东西声明为
()->(
)时,SwiftLint强迫我将其键入
()->Void
!我想知道这是什么原因?应该是一样的吗?!我们已经知道,
Void
()
的类型别名。。。在做了一个快速的调查之后,我发现
()->Void
更好地用于匹配Objective-C世界中的返回约定。这可能意味着有一个不同的:)此外,如果你检查一下,我们会注意到-可能出于某种原因-他们只使用
()->Void
,而不是
()->()
。@AhmadF我怀疑这与
()->()
没有转换为
()->Void
有关,但是
异步(执行:(bar?.bar???{})as()->())
神奇地编译…还有一件有趣的事情是:尽管
DispatchQueue.main.async(execute:bar?.bar???{})
产生错误,在常量和pass中声明闭包将使其工作:
let closure=bar?.bar???{}DispatchQueue.main.async(execute:closure)
在这一点上,你认为应该报告一个bug还是什么?还是我们遗漏了什么?@AhmadF让我们等一会儿,看看其他人是否知道发生了什么。