Область видимости и синтаксис вызова вложенных функций - PullRequest
4 голосов
/ 09 марта 2012

Я пытаюсь вызвать вложенную рекурсивную функцию perl, но не могу определить правильный синтаксис.

Вопрос : Каков правильный синтаксис для выполнения рекурсивного вызова для вложенной функции (если вложенные функции вообще должны вызываться рекурсивно)?

Ответ: Обратитесь к предлагаемому псевдокоду в принятом ответе.

Вот фрагмент псевдокода:

use Scalar::Util;
sub outerfunction {
  my $innerfunction = sub {
    # Do something
    innerfunction(); 
    # Do other things
  }; 
  Scalar::Util::weaken($innerfunction); 
  &$innerfunction(@_);
}; 

Я попытался вызвать внутреннюю функцию следующим образом (с соответствующими сообщениями об ошибках):

innerfunction

Неопределенная подпрограмма и главная :: внутренняя функция

&innerfunction

Не определенная подпрограмма и главная :: внутренняя функция

&$innerfunction

Глобальному символу "$ innerfunction" требуется явное имя пакета

Я также пытался объявить внутреннюю функцию как локальную, но получил следующее:

Глобальный символ "$ innerfunction" требует явного имени пакета

У меня нет большого опыта работы с интерпретируемыми языками, поэтому любые непредвиденные комментарии, связанные с утечкой памяти / стеком / повреждением или другими опасностями сh также будет высоко оценен приведенный выше псевдокод (кроме системных ограничений на рекурсию).

Спасибо!Perl v5.10.1 работает в Linux 2.6.34.7-61.fc13.x86_64

Ответы [ 2 ]

14 голосов
/ 09 марта 2012

Синтаксис innerfunction() доступен только для подпрограмм, которые установлены в таблицу символов (например, для синтаксиса sub NAME {...}).Вам нужно вызывать вашу внутреннюю функцию как $innerfunction->() или &$innerfunction(), но у вас возникают проблемы с областью действия $innerfunction лексического.

Когда вы объявляете переменную с my,переменная находится в области действия после , когда этот оператор заканчивается.Поэтому вам нужно разделить объявление:

 my $innerfunction;
    $innerfunction = sub {
        ...
        $innerfunction->();
        ...
    };

Чтобы разбить циклическую ссылку на weaken, обычный шаблон выглядит так:

use Scalar::Util;
sub outer_function {
    my $weak_ref;
    $weak_ref = my $strong_ref = sub {
        # Do something
        $weak_ref->(); 
        # Do other things
    };
    Scalar::Util::weaken($weak_ref); 
    return $strong_ref;
};

Итак, как только $strong_ref идетвне области, подпрограмма будет собирать мусор.

4 голосов
/ 09 марта 2012
sub outer_function {
    local *inner_function = sub {
        # Do something
        inner_function(); 
        # Do other things
    };
    inner_function();
};

почти так же хорош, как и следующие, но гораздо яснее:

use Scalar::Util qw( weaken );
sub outer_function {
    my $weak_ref;
    my $strong_ref = sub {
        # Do something
        $weak_ref->(); 
        # Do other things
    };
    weaken($weak_ref = $strong_ref);  # Avoid memory leak.
    $strong_ref->();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...