2015-01-20 3 views
0

В некоторых функциях perl я хочу иметь возможность работать с различными типами аргументов и, конечно, относиться к ним по-разному. Теперь я использую для этой функции ref и выполняю соответствующую часть кода на основании результата ref, например.Perl - как создать функцию, которая принимает различные типы данных

sub method_that_accept_various_data_types(){ 
    if (ref $_[0] eq "ARRAY"){ 
    # ... 
    } 
    elsif (ref $_[0] eq "SCALAR"){ 
    # ... 
    } 
    elsif (ref $_[0] eq "HASH"){ 
    # ... 
    } 
} 

Есть некоторые элегантный способ, с помощью которого я могу сказать, что все мои функции должны следовать этому образцу, или я должен использовать указанный код в начале всех моих подпрограмм? Я пишу процедурный код, и я думаю, что что-то похожее - это полиморфизм и наследование в ООП, но я новичок в этой области.

Редактировать Все ответы должны добавить код ко всей вновь созданной функции. Я спрашиваю, есть ли какой-то общий способ сделать это для каждой функции, определенной с этого момента, без необходимости добавления кода в новую функцию.

+2

Вы не должны выполнять такие функции, как они по своей сути являются ошибками – ikegami

+0

Почему? Можете быть более конкретными? –

+1

Потому что что-то может быть как хэш, так и массив (и т. Д.). Если вы не хотите предоставлять несколько функций, основывайте свой полиморфизм на количестве аргументов или имени аргументов (при использовании аргументов 'foo => $ foo'). – ikegami

ответ

1

Вы также можете использовать хэш функций/отправка таблицы, но это в основном тот же подход,

sub method_that_accept_various_data_types { 

    my $ref = ref($_[0]); 

    my $func = { 
    ARRAY => sub { 
     print "$ref\n"; 
    }, 
    SCALAR => sub { 
     print "$ref\n"; 
    }, 
    HASH => sub { 
     print "$ref\n"; 
    }, 
    }->{$ref} or return; 

    $func->(@_); 
} 
+0

Обязательно передайте '@ _' анонимному подпункту, потому что он больше не сможет получить доступ к внешнему' @ _'. –

+0

@ DanielBöhmer tnx для комментария. –

+0

С недавним редактированием вы удаляете 1-й элемент интереса от '@ _' и * не * передаете его в суб! Придерживайтесь '$ _ [0]'. –

0

Вы можете использовать switch заявление от Switch module

use Switch; 

sub polymorph_function { 
    my ($arg1, $arg2, ...) = @_; 

    switch (ref $arg1) { 
     case 'ARRAY' { ... } 
     case 'HASH' { ... } 
     ... 
    } 
} 
+1

Переключатель не рекомендуется. Это исходный фильтр, он может вызвать странные ошибки. – choroba

+0

В качестве альтернативы, если вы знаете, что ваш код будет работать только на Perl 5.10.1 или выше, вы можете использовать [функцию 'switch'] (http://perldoc.perl.org/perlsyn.html#Switch-Statements). Это почти то же самое, но с разными ключевыми словами: 'for' или' given' и 'when'. –

0

Я добавляю это на примере Сухой27 как дополнительный ответ, потому что я лично считаю его плохим кодом. Но если вы предпочитаете короткий код, который вы хотели бы его:

sub polymorph_function { 
    ({ 
     ARRAY => sub { ... }, 
     HASH => sub { ... }, 
     ... 
    }->{ref $_[0]} || return)->(@_); 
} 

Это в основном те же, за исключением того, что не существует никаких временных переменных. Он создает анонимный хеш, и его ссылка непосредственно разыменовывается, и соответствующий ключ выбирается на основе ref $_[0] (тип 1-го аргумента). Затем полученный coderef к одному из подсетей вызывается сразу со всеми аргументами в исходное под.

+1

Правильно. Компактный код становится еще хуже :-) –

-1

Я просто подумал о способах перемещения большей части кода в центральное место.

sub polymorph_function { 
    poly \@_, (
     ARRAY => sub { ... }, 
     HASH => sub { ... }, 
     ... 
    ); 
} 

sub poly { 
    my ($args, %subs) = @_; 

    my $sub = $subs{ref $args->[0]} or return; 
    $sub->(@$args); 
} 
Смежные вопросы