Поиск

Подробнее о функциях

Многие технические приемы программирования, как, например, рекурсивный вызов функций, могут быть эффективно реализованы только с учетом области видимости переменных. К этому вопросу непосредственное отношение имеет оператор use strict, ужесточающий синтаксический контроль в Perl, что позволяет избежать некоторых грубых ошибок.

Объявление переменных с помощью оператора local

В Perl версии 4 не было по-настоящему приватных переменных. Вместо них в Perl 4 были "почти" приватные переменные. Концепция "почти" приватных переменных до сих пор присутствует и в Perl 5. Мы будем называть такие переменные локальными. Для объявления этих переменных используется оператор local:

В этом примере объявляется локальная переменная $foo подпрограммы myfuncf(). Поведение переменной, объявленной с помощью оператора local, почти не отличается от поведения переменной, объявленной с помощью оператора my. Областью видимости локальной переменной может быть подпрограмма, блок или конструкция eval. При завершении подпрограммы или блока эта переменная аннулируется.

Отличие состоит в том, что переменная, объявленная локальной, видима не только в пределах того блока, в котором она объявлена, но и во всех подпрограммах, вызванных из этого блока. В табл. 8.1 приведено сравнение приватных и локальных переменных.

Два фрагмента текста, приведенные в табл. 8.1, практически идентичны, за исключением объявления переменной $foo в функции myfuncf(). Слева эта переменная объявлена как приватная, а справа — как локальная.

В коде слева функция mess_with_foo() изменяет глобальную переменную $foo. После возвращения управления в myfunc{) будет напечатано число 20, так как приватная переменная $foo, принадлежащая этой функции, не была изменена.

В коде справа в функции mess_with_foo() создается локальная переменная $foo. Затем функция mess with foo(} устанавливает для переменной $foo значение 0. Это та же переменная, что и вmyfunc(),~ — локальные переменные передаются в подпрограммы. После возвращения в myfunc() будет напечатано значение 0.

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

Итак, если вам нужно объявить по-настоящему приватную переменную, используйте оператор ray.

Как сделать Perl строже

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

При разработке больших программных проектов (особенно по мере усложнения программы) было бы неплохо, чтобы Perl хоть как-то удерживал вас от совершения случайных ошибок. Кроме ключа -w, в интерпретаторе Perl имеются и другие средства для вывода дополнительных предупреждений во время компиляции. Для этого используется оператор use strict:

Оператор use strict называется директивой компилятора. Эта директива указывает Perl, что необходимо отслеживать перечисленные ниже ситуации и выводить сообщения об ошибках времени выполнения с информацией о текущем файле и блоке.

  • Использование имени переменной, не являющейся специальной, без ее объявления в операторе my.
  • Использование недопустимого имени функции (без & и скобок) перед тем, как эта функция была определена.
  • Другие потенциальные ошибки

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

Другая ловушка, выпутаться из которой помогает директива use strict, — использование недопустимых ключевых слов. Посмотрите на код

$var=value;

В данном случае непонятно, что такое value — строка без кавычек или имя функции. При использовании директивы use strict Perl сообщит, что этот код непонятен и синтаксически недопустим, если только соответствующая функция предварительно не определена.

С этого момента все примеры и относительно длинные листинги в книге будут содержать директиву use strict.

Рекурсия

Рано или поздно вы познакомитесь со специальным классом подпрограмм. Во время своей работы эти подпрограммы вызывают сами себя. Они называются рекурсивными подпрограммами.

Рекурсивные подпрограммы используются в случае, если задача может быть сведена к решению более простой идентичной задачи, а та, в свою очередь, — к еще более простой, и т.д. Одна из рекурсивных задач — поиск файла в древовидной структуре каталогов: вначале поиск ведется в самом верхнем каталоге, затем наступает очередь подкаталогов и т.д. Как видите, в данном случае подзадачи идентичны основной задаче.

Другая рекурсивная задача связана с вычислением факториалов. Факториалы используются в статистике. Количество перестановок букв ABCDEF равняется факториалу шести. Факториал — это произведение всех целых чисел, меньших данного, включая 1. Например, факториал числа 6 — 6x5x4x3x2x1 или 720. Для вычисления факториала 6 необходимо факториал 5 умножить на 6. Для вычисления факториала 5 Необходимо факториал 4 умножить на 5 и т.д. Рекурсивная функция для нахождения факториалов приведена в листинге 8.3.

Проведем анализ программы.

  • Строка 2. Аргумент подпрограммы factorial() присваивается переменной $num, которая объявлена в данной подпрограмме как приватная.
  • Строка 3. Для каждой рекурсивной функции необходимо предусмотреть условие прекращения. Это то значение аргумента, при котором функция больше не вызывает сама себя. Для подпрограммы factorial() условие прекращения — это вычисление факториала 1 или 0. Два приведенных значения равны единице, поэтому подпрограмма factorial(), вызванная с аргументом 0 или 1, выполняет код return(l) (это случай $num<=1).
  • Строка 4. Если аргумент не равен нулю или единице, вычисляется факториал предыдущего числа, как показано ниже.

В результате выполнения цепочки вызовов рекурсивных функций будут последовательно вычислены факториалы всех чисел, меньших данного. Их значения по цепочке передаются в вызвавшие их функции, и в конце концов вычисляется значение факториала 6.

Рекурсивные функции встречаются не часто. Большие рекурсивные функции тяжело создавать и отлаживать. Любая задача, решаемая с помощью циклов for, while, foreach, может быть решена при помощи рекурсии, и, наоборот, всякая рекурсивная задача может быть выполнена с помощью циклов. Рекурсивные процедуры обычно используются для решения относительно небольшого круга задач, естественным образом формализуемых с помощью метода рекурсии.