Почему я не могу передать определенные выражения параметру закрытия, помеченному @convetion (block)? - PullRequest
0 голосов
/ 17 января 2019

Я обнаружил это странное поведение:

Рассмотрим следующий код:

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

}

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

var bar: Bar? = Bar()

Эти компиляции:

foo(bar?.bar ?? {})

но это не так:

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).

Гипотеза: Я не могу передать необязательные выражения цепочки в параметры, отмеченные @convention(block).

Но, похоже, это неправильно, так как я могу это сделать, но он по-прежнему не компилируется:

DispatchQueue.main.async(execute: Bar().bar ?? {})

Также кажется, что я могу привести выражение к () -> Void, и оно волшебным образом компилируется:

DispatchQueue.main.async(execute: (bar?.bar ?? {}) as () -> Void)

Не является ли bar?.bar ?? {} уже типа () -> Void? Это не имеет смысла!

Другой способ сделать его компилируемым - извлечь bar?.bar как локальную переменную:

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

что имеет еще меньше смысла ...

...