Как написать подпрограмму Perl, которая работает как обычная подпрограмма или метод класса? - PullRequest
3 голосов
/ 24 июня 2009

Я пишу функцию, которая в основном статична по своей природе. Я хочу подключить его к Template Toolkit, который передает имя класса. По сути, это делает

ClassName->function( $args.. )

но я хочу что-то вроде

ClassName::function( $args.. )

внутри

sub function {
}

Как правильно обрабатывать оба случая?

Ответы [ 3 ]

7 голосов
/ 24 июня 2009

В общем, нет.sub либо записывается для вызова в качестве метода, либо нет.

Посмотрите, как File :: Spec :: Functions обрабатывает эту ситуацию, добавляя имя пакета ксписок аргументов.

Теперь, в очень конкретном, ограниченном регистре , вы можете сделать:

shift if $_[0] eq __PACKAGE__;

в качестве первой строки в вашемsub, чтобы отбросить первый аргумент, когда sub вызывается как метод класса.

6 голосов
/ 24 июня 2009

Вот более безопасная версия, сочетающая в себе ответы Синана и Алана , а также:

  • Обрабатывает возможность вызова метода из производного объекта
  • Не будет неправильно истолковывать ClassName::function("ClassName") как вызов метода

код:

if (@_ == $nArgsExpectedForThisFunc + 1) {
    $_[0] eq __PACKAGE__ || UNIVERSAL::isa($_[0], __PACKAGE__) || die;
    shift;
}

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

4 голосов
/ 24 июня 2009

Template Toolkit ожидает, что его плагины будут использовать OO, поэтому нет никакого способа предоставить этот интерфейс. Если вам также нужен функциональный интерфейс, у вас есть несколько вариантов.

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

ClassName::function('ClassName', @args);

но это грязно. Более чистым решением было бы разделить его на две субмарины с одной оберткой для другой. например,

package ClassName;

sub function {
    # do something
}

sub method {
    my $class = shift;
    function(@_);
}

Функция также может быть оболочкой для метода. Как упоминал Синан, File :: Spec делает это путем создания двух модулей: одного с интерфейсом OO и одного с функциональным интерфейсом.

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