ПрограммированиеBackend разработчик

Как в Perl работают списочные операции map и grep? В чем их различия и как избежать неожиданных побочных эффектов при их использовании?

Проходите собеседования с ИИ помощником Hintsage

Ответ

map и grep — это мощные функции Perl для работы с массивами:

  • map применяет выражение к каждому элементу списка и возвращает новый список с результатами.
  • grep возвращает элементы списка, для которых выражение возвращает истинное значение (фильтрация).

Пример использования:

my @nums = (1, 2, 3, 4, 5, 6); my @squared = map { $_ * $_ } @nums; # (1, 4, 9, 16, 25, 36) my @even = grep { $_ % 2 == 0 } @nums; # (2, 4, 6)

Важно

  • Область видимости: Внутри блоков map и grep переменная $_ по умолчанию содержит текущий элемент. Модификация $_ изменит сам элемент исходного массива, если массив передан по ссылке или явно используется $_ (например, при alias через foreach).
  • Возвращаемые значения: map всегда возвращает список, grep — подмножество оригинального списка.

Вопрос с подвохом

Вопрос: Что делает следующий код и почему?

my @nums = (1..5); my @result = map { $_++ } @nums; print "@nums ";

Ответ: Этот код не изменит исходный массив @nums. Оператор $_++ увеличивает значение переменной внутри блока, но не сохраняет эти изменения в исходном массиве, т.к. map возвращает измененное значение, но оригинальный массив не затронут (если только не используется alias через foreach).

Пример:

my @nums = (1..5); my @result = map { $_++ } @nums; # @result будет (1,2,3,4,5), @nums не меняется print "@nums "; # Выведет: 1 2 3 4 5

Примеры реальных ошибок из-за незнания тонкостей темы


История В одном проекте разработчик ожидал, что после map { $_++ } @array, сам массив @array будет изменен. В результате программа продолжала работать со старыми значениями, что привело к неверным подсчетам при агрегации данных.


История В отчетной системе при фильтрации массива через grep, внутри блока случайно использовали команду присваивания $result = $_, из-за чего все элементы были перезаписаны в одну и ту же переменную, потеряв источник данных. Это усложнило отладку и привело к потерям в отчетности.


История В интеграционном скрипте кода применяли вложенные map и забыли, что внутренний контекст также работает с общей переменной $_, что вызвало непредсказуемое поведение при модификации элементов, так как внутренний map затер значения в результирующем массиве.