Функция вызывается, но не выполняется

У меня есть этот пользовательский оператор:

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()
Другие вопросы по тегам