Функция вызывается, но не выполняется
У меня есть этот пользовательский оператор:
infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: @autoclosure ()->Any) {
if lhs == nil {
print("lhs is nil")
rhs()
}
}
Использование:
optional ?> {
print("executing")
}
Проблема в том, когда lhs
ноль, закрытие не выполняется. В консоли "lhs is nil" печатает, но потом "executing" не печатает. Как выполняется оператор печати "lhs is nil", но не rhs
?
4 ответа
Похоже, что решение заключается в добавлении перегрузки оператору с точно такой же сигнатурой, за исключением того, что он не имеет @autoclosure
аннотация, и rhs
для обоих должен вернуться Void
вместо Any
,
infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: @autoclosure ()->Void) {
if lhs == nil {
print("lhs is nil")
rhs()
}
}
func ?> (lhs: Any?, rhs: ()->Void) {
if lhs == nil {
print("lhs is nil")
rhs()
}
}
Таким образом, если я делаю:
optional ?> doSomething()
@autoclosure
один будет вызван, независимо от того, doSomething()
возвращает что-нибудь или нет.
И если я сделаю:
optional ?> {
doSomething()
doSomethingElse()
}
тот без @autoclosure
будет вызван, потому что закрытие имеет тип ()->Void
,
То, что вызывает такое поведение @autoclosure
, если вы удалите его, он работает нормально.
Это потому что @autoclosure
превратит ваше закрытие в закрытие, так что теперь у вас есть что-то вроде этого:
{ { print("executing") } }
Внешнее закрытие возвращается Any
, право? Так что это просто вернет закрытие { print("executing") }
и больше ничего не делать.
Если вы хотите сохранить @autoclosure
Вы можете использовать оператор следующим образом:
optional ?> print("executing")
Вам нужно добавить ()
в конце метода закрытия, как показано ниже
optional ?> {
print("executing")
}()
Если ваше намерение, что фигурные скобки должны быть добавлены после оператора, вы можете реализовать его (без необходимости объявления rhs
как автозаполнение) как:
infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: ()->Any) {
if lhs == nil {
print("lhs is nil")
rhs()
}
}
var myString: String? = ""
// some case that made "string" to be nil...
myString = nil
myString ?> {
print("executing")
}
Однако цель объявления автозаполнения состоит в том, чтобы обернуть выражение, передаваемое в качестве аргумента функции:
Это синтаксическое удобство позволяет опускать скобки вокруг параметра функции, записывая нормальное выражение вместо явного замыкания.
Официальная документация Swift - закрытие, автозаполнение
Это означает, что в фигурных скобках нет необходимости, что должно быть более естественным при работе с оператором:
infix operator ?> : NilCoalescingPrecedence
func ?> (lhs: Any?, rhs: @autoclosure ()->Any) {
if lhs == nil {
print("lhs is nil")
rhs()
}
}
var myString: String? = ""
// some case that made "string" to be nil...
myString = nil
// you could use your operator like:
myString ?> print("executing")
Но ждать!
Может возникнуть проблема, которая заключается в следующем: что, если после оператора следует добавить кусок кода?
Ну, без сомнения, вы должны добавить фигурные скобки:
let doSomething = {
print("executing")
print("second line of execution")
print("third line of execution")
}
myString ?> doSomething()