Ошибка при создании замыкания внутри функции - PullRequest
0 голосов
/ 30 мая 2018

Большое спасибо за ответ.На этом этапе я учусь писать замыкания.На самом деле я где-то читал о функции "forEach", которая работает с коллекциями и принимает в качестве параметра один аргумент (т. Е. Замыкание).

Синтаксис forEach: "Void forEach (body: (Int) throws ->)Void) rethrows "

То, что я пытаюсь сделать, это написать аналогичную функцию с одним параметром (т. Е. Замыканием), который вычислит факториал числа, и мы можем вывести факториал этого числа.Я не хочу передавать это число в качестве второго параметра этой функции.

Я понимаю, что forEach - это функция-член класса Collections, которая работает с каждым элементом по одному.Таким образом, он выбирает элементы из массива.Точно так же я создал частное свойство (factorialNumber) внутри моего класса (значение которого я могу установить, используя открытую функцию "setFactorialNumber").Теперь я пытаюсь создать публичную функцию (factorial) для моего класса, которая будет иметь только один параметр (т.е. замыкание), который будет использовать значение свойства «factorialNumber» внутри и вычислять факториал этого числа, который мы можем напечатать извнекогда мы вызываем эту функцию из другого кода.

Ниже мой класс ..

public class MyArray {
    private var factorialNumber = 0

    public func setFactorialNumber(factorialNumber value: Int) {
        factorialNumber = value
    }

    public func factorial(body closure: (Int) -> Void) -> Void {
        var outputString: String?
        var result = 1

        if factorialNumber <= 0 {
            outputString = nil
        } else {
            outputString = ""
            while(factorialNumber >= 1) {
                if factorialNumber == 1 {
                    outputString = outputString! +  "\(factorialNumber) = \(result)"
                    break
                } else {
                    outputString = outputString! + "\(factorialNumber) x "
                }
                result = result * factorialNumber
                factorialNumber -= 1
            }
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Закрытие - это, по сути, функция, которую нужно вызвать.
В вашем случае вы определяете ее, но не используете.

Проблемы, которые я вижу в factorial(body:):

  1. Вы должны выполнить замыкание как минимум один раз.
    т.е. выполнить в какой-то момент / с следующие действия:

    closure(someValue)
    
  2. Вы, похоже, поддерживаете outputString, который выглядит как то, что вы хотите, чтобы закрытие взяло.
    В этом случае ваше закрытие должно занять String вместоInt.

    func factorial(body closure: (String?) -> Void) -> Void { //...
    

Наконец, вот как должна выглядеть функция:

func factorial(body closure: (String?) -> Void) -> Void {
    var outputString: String?

    //...your factorial logic as:
    if factorialNumber <= 0 {
        outputString = nil
    } else {
        outputString = ""
        while(factorialNumber >= 1) {
            if factorialNumber == 1 {
                outputString = outputString! +  "\(factorialNumber) = \(result)"
                break
            } else {
                outputString = outputString! + "\(factorialNumber) x "
            }
            result = result * factorialNumber
            factorialNumber -= 1
        }
    }

    //Finally, the closure call
    closure(outputString)
}

И, глядя на вашу структуру, этоиспользование будет:

let factorial = MyArray()
factorial.setFactorialNumber(factorialNumber: 20)
factorial.factorial { (result) in
    print(result)
}

Вывод будет:

20 х 19 х 18 х 17 х 16 х 15 х 14 х 13 х 12 х 11 х 10 х 9 х8 x 7 x 6 x 5 x 4 x 3 x 2 x 1 = 2432902008176640000


ПРИМЕЧАНИЕ. Ваш класс является Crashable

Ответ выше достаточно для конкретного контекставашего вопроса, но обратите внимание:

  1. Ваша логика использует Int, поэтому числа больше 20 приводят к сбою кода

    Решение:

    • Использование Double
    • Защитите свою логику от сбоев на входах, слишком больших для обработки
  2. Если вы не setFactorialNumber(factorialNumber:) и сразу перейдете к вызову factorial(body:), вашкод будет зависать.


Улучшение?:

  • Изменить имя класса с MyArray на FactorialFinder или что-то
  • Добавьте init к этому классу:

    init(with number: Int) {
        self.factorialNumber = number
    }
    
  • Теперь, когда у нас есть пользовательский init, сделайте значение по умолчанию init private:

    private init() {}
    
    • Так что подобное не возможно FactorialFinder()
    • И FactorialFinder(with:) становится единственным способом инициализации этого класса
0 голосов
/ 30 мая 2018

Ваш первый пример является хорошим намеком на вашу проблему:

factorial {
 print("Factorial is: \($0)")
}

Что такое точный текст , который вы хотите, чтобы эта функция печатала?«Факториал равен: 100», «Факториал равен: 200»?

Это вопрос с подвохом, потому что ответ неизвестен: ваша функция не принимает число для вычисления факториала, она принимает толькозавершающее замыкание, определяющее, что делать с результатом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...