Чтобы ответить на ваш конкретный вопрос: нет, с точки зрения изучения языка рекурсия не является функцией. Если ваш профессор действительно поставил вам оценки за использование «функции», которой он еще не обучал, это было неправильно.
Если читать между строк, одна из возможностей состоит в том, что, используя рекурсию, вы никогда не использовали функцию, которая должна была стать результатом обучения для его курса. Например, возможно, вы вообще не использовали итерацию, или, может быть, вы использовали только for
циклы вместо использования обоих for
иwhile
. Часто задание направлено на проверку вашей способности делать определенные вещи, и если вы избегаете их выполнять, ваш профессор просто не сможет выставить вам оценки, установленные за эту функцию. Однако, если это действительно было причиной ваших потерянных оценок, профессор должен воспринимать это как свой собственный учебный опыт - если демонстрация определенных результатов обучения является одним из критериев для задания, это следует четко объяснить студентам. ,
Сказав это, я согласен с большинством других комментариев и ответов, что итерация здесь лучше, чем рекурсия. Есть несколько причин, и, хотя другие люди в какой-то мере их коснулись, я не уверен, что они полностью объяснили стоящую за ними мысль.
Переполнение стека
Более очевидным является то, что вы рискуете получить ошибку переполнения стека. На самом деле, очень маловероятно, что написанный вами метод приведет к такому результату, поскольку пользователю придется вводить неверные данные много раз, чтобы вызвать переполнение стека.
Однако следует иметь в виду, что не только сам метод, но и другие методы выше или ниже в цепочке вызовов будут находиться в стеке. Из-за этого случайное поглощение доступного пространства стека - довольно невежливая вещь для любого метода. Никто не хочет постоянно беспокоиться о свободном пространстве стека при написании кода из-за риска того, что другой код может без нужды использовать его много.
Это часть более общего принципа разработки программного обеспечения, называемого абстракцией. По сути, когда вы звоните DoThing()
, все, о чем вам нужно заботиться, - это то, что Вещь сделана. Вам не нужно беспокоиться о деталях реализации того, как это делается. Но жадное использование стека нарушает этот принцип, потому что каждый бит кода должен беспокоиться о том, сколько стека он может безопасно предположить, оставив ему код в другом месте цепочки вызовов.
читабельность
Другая причина - удобочитаемость. Идеал, к которому должен стремиться код, - это быть удобочитаемым документом, где каждая строка просто описывает то, что он делает. Возьмите эти два подхода:
private int getInput() {
int input;
do {
input = promptForInput();
} while (!inputIsValid(input))
return input;
}
против
private int getInput() {
int input = promptForInput();
if(inputIsValid(input)) {
return input;
}
return getInput();
}
Да, они оба работают, и да, их обоих довольно легко понять. Но как эти два подхода можно описать на английском языке? Думаю, это будет примерно так:
Я буду запрашивать ввод, пока ввод не станет действительным, а затем верну его
против
Я запрошу ввод, затем, если ввод действителен, я верну его, в противном случае я получу ввод и вместо этого верну результат
Возможно, вы можете придумать несколько менее неуклюжую формулировку для последнего, но я думаю, вы всегда обнаружите, что первая будет более точным концептуальным описанием того, что вы на самом деле пытаетесь сделать. Это не значит, что рекурсия всегда менее читабельна. Для ситуаций, когда это хорошо, например, обход дерева, вы можете провести такой же параллельный анализ между рекурсией и другим подходом, и вы почти наверняка обнаружите, что рекурсия дает код, который более четко описывает сам себя, строка за строкой.
По отдельности это мелочи. Маловероятно, что это когда-либо действительно приведет к переполнению стека, а улучшение читаемости незначительно. Но любая программа будет набором множества этих небольших решений, поэтому, даже если по отдельности они не имеют большого значения, важно изучить принципы, лежащие в основе их правильного принятия.