Как объявить функцию переброски?

Я реализовал следующую функцию как расширение массива логических значений, которая могла вызвать ошибку CustomError:

enum CustomError: Error {
    case empty
    case doesNotContainTrue
}

extension Array where Element == Bool {
    func indexOfFirstTrue() throws -> Int {
        if isEmpty { throw CustomError.empty }

        guard let detectedIndex = index(of: true) else {
            throw CustomError.doesNotContainTrue
        }

        return detectedIndex
    }
}

который работает так, как ожидалось:

let myArray = [false, true, false, true]
try print(myArray.indexOfFirstTrue()) // 1

Затем я попытался объявить функцию как:

func handleResult(_ index: Int) throws {
    print(index * 2)
    // ...
}

который должен взять результат myArray.indexOfFirstTrue() и что-то с ним сделать (для простоты предположим, что он печатает значение, умноженное на 2):

try handleResult(myArray.indexOfFirstTrue()) // 2

Что я хочу сделать, так это объявить handleResult как функция повторного броска:

Функция или метод могут быть объявлены с ключевым словом rethrows, чтобы указать, что они выдают ошибку, только если один из ее параметров функции выдает ошибку. Эти функции и методы известны как функции повторного генерирования и методы повторного генерирования. Функции и методы повторного генерирования должны иметь по крайней мере один параметр функции генерирования.

Язык программирования Swift (Swift 4.1): Объявления — повторное создание функций и методов.

Поэтому я могу вызвать его с помощью формулы без выбрасывания, поэтому он не будет выдавать ошибку:

handleResult(myArray.indexOfFirstTrue()) // 2

Но я застрял в том, что я должен отредактировать, чтобы это была функция повторного броска, поэтому я попытался объявить ее как:

func handleResult(_ index: Int) rethrows {
    print(index * 2)
}

и я получил ошибку:

ошибка: функция 'rethrows' должна принимать аргумент функции броска

поэтому я также попытался объявить это как:

func handleResult(_ index: (() throws ->  Int)) rethrows {
    print(index * 2)
}

и, очевидно, получил ошибку:

ошибка: невозможно преобразовать значение типа «Int» в ожидаемый тип аргумента «() throws -> Int»

Что мне делать в этот момент?


person Ahmad F    schedule 05.04.2018    source источник
comment
Почему handleResult должен перебрасывать? Насколько я могу судить, вы просто хотите, чтобы indexOfFirstTrue бросил. Вы бы по-прежнему называли это try handleResult(myArray.indexOfFirstTrue()).   -  person Hamish    schedule 05.04.2018
comment
Не имеет отношения, но ваша логика для получения detectedIndex может быть упрощена до guard let detectedIndex = index(of: true) else { throw CustomError.doesNotContainTrue }.   -  person Hamish    schedule 05.04.2018
comment
Спасибо за заметку @Hamish :)   -  person Ahmad F    schedule 05.04.2018


Ответы (1)


Помните, аргумент имеет тип () -> Int! Поэтому вам нужно вызвать переданную функцию, чтобы получить результат! Вам также нужно try, так как функция может бросать.

func handleResult(_ index: (() throws ->  Int)) rethrows {
    print(try index() * 2) // see the "()"?
}

Теперь вы можете использовать его так:

let myArray = [true]
try handleResult(myArray.indexOfFirstTrue)
person Sweeper    schedule 05.04.2018
comment
Спасибо друг. основываясь на вашем ответе, мне все еще приходится называть это try (try handleResult(myArray.indexOfFirstTrue)), чего я пытаюсь избежать. Итак, что я должен сделать, чтобы иметь возможность звонить как handleResult(myArray.indexOfFirstTrue)? - person Ahmad F; 05.04.2018
comment
@AhmadF Тогда вам нужно обработать ошибку внутри handleResult и удалить rethrows. - person Sweeper; 05.04.2018
comment
То, что вы упомянули, кажется мне логичным, однако я хотел бы знать, как тогда работает логика функции map?! как упоминалось в этом ответе, map может принимать функцию без выбрасывания, что не разрешено в моем случае, если мы попытаемся to: func getValue() -> Int { return 2 } handleResult(getValue()) это не сработает. ценю ваше терпение ???? - person Ahmad F; 05.04.2018
comment
@AhmadF Вы должны передать getValue без скобок: handleResult(getValue) Помните, что вы не вызываете функцию! Кроме того, вы можете написать это так handleResult { 2 } - person Sweeper; 05.04.2018
comment
мой Бог! о, чувак, я только что сделал ту же ошибку... Вот что я имел в виду: я хочу назвать это без try (handleResult { 1 }). - person Ahmad F; 05.04.2018