Плохая практика для метода вызывать себя? - PullRequest
2 голосов
/ 07 октября 2019

У меня вопрос о хорошей или плохой практике.

Я создал функцию, которая будет генерировать случайное число. И если случайное число равно предыдущему случайному числу, оно должно генерировать новое число. Итак, мой вопрос. Это плохая практика вызывать тот же метод из метода?

func getRandomNumber(){ //<-- Method name
    let randomNumber = Int.random(in: 0..<allPlayers.count)

    if lastRoundNumber == randomNumber{
        getRandomNumber() //<-- Like this
    }
    print(randomNumber)
}

Или я должен сделать это другим способом? Если да, то как?

Так что плохая практика - вызывать тот же метод из текущего метода, который я делал в приведенном выше коде? Заранее спасибо.

Если да, то почему это плохо? И как вы можете сделать это, чтобы получить «лучший» код?

Ответы [ 2 ]

5 голосов
/ 07 октября 2019

Нет ничего плохого в том, чтобы вызывать саму функцию. Это называется рекурсия . Если не реализовано должным образом, это может привести к некоторым накладным расходам, но иногда это может быть очень элегантным решением.

При этом, возможно, вы не захотите делать это так, как здесь. Что, если он угадал одно и то же число три раза, прежде чем получил тот, который не был равен lastRoundNumber? Вы увидите четыре print операторов для одного нового значения. Вы действительно хотите такое поведение? Если вы собираетесь реализовать getRandomNumber как рекурсивную функцию, по крайней мере, я бы предложил вставить оператор return после того, как он вызывает себя рекурсивно, чтобы вы не получили print операторов для итераций, где онав итоге получили то же значение, что и lastRoundNumber.

. Как уже было сказано, мы часто достигаем рекурсии (и сопутствующих издержек), когда эта реализация заметно более элегантна или интуитивна, чем нерекурсивное представление,Но в этом случае нерекурсивное представление, вероятно, столь же ясно, и, как таковое, мы, скорее всего, предпочли бы его рекурсивной версии. Это может выглядеть так:

func getRandomNumber() {
    guard allPlayers.count > 1 else { return }

    var randomNumber: Int

    repeat {
        randomNumber = .random(in: 0..<allPlayers.count)
    } while randomNumber == lastRoundNumber

    print(randomNumber)
}

Обратите внимание, я проверяю, что у вас есть более одного игрока, чтобы избежать возможности бесконечного цикла.


Но скажем, было 100игроки. И скажем, вы называли это 100 раз. Это нормально, если он вернул игрока 1, затем игрока 2, затем игрока 1 снова, затем игрока 2 снова, повторяя снова и снова, никогда не возвращая игроков с 3 по 100. Это маловероятно, но возможно. Это нормально?

Часто мы хотим вернуть всех игроков, но в случайном порядке. В этом случае вы «перетасуете» список, например,

let players = (0..<allPlayers.count).shuffled()

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

Это зависит только от вашего желаемого поведения.

1 голос
/ 07 октября 2019

Если вы вызываете метод из того же метода, он называется рекурсией. Вы можете найти здесь объяснение того, как работает рекурсия в swift. Вы должны убедиться, что у вашего метода есть условие выхода, чтобы вы не застряли в своем вызове.

Давайте рассмотрим пример вызова вашего метода. lastRoundNumber равно 1. Ваш сгенерированный номер также равен 1. Поэтому он снова вызовет метод. Затем вы сгенерируете число 2.

С помощью print(randomNumber) вы получите следующий вывод:

2
1

Это произойдет, потому что оператор print будет выполнен, даже если вывызовите метод еще раз.

Так что вам нужно переделать ваш оператор if в следующее:

if lastRoundNumber == randomNumber{
    getRandomNumber() //<-- Like this
} else {
    print(randomNumber)
}

Таким образом, он будет печатать только последнее сгенерированное значение

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