Ссылка от возвращаемого значения до параметра - PullRequest
1 голос
/ 05 января 2012

Предположим, у нас есть подпрограмма, возвращающая ссылку

sub aspirin {
    my @items = qw(some items in here);
    return \@items;
}

И еще одна подпрограмма, принимающая ссылку на массив

sub beetroot (\@) {
    my $lst = shift;
    print "$_\n" for @$lst;
}

Я хочу получить массив из aspirin и feed beetroot с этим.Я хотел бы сделать что-то вроде (подход A )

my $L = aspirin;
beetroot $L;

Но переводчик жалуется, и мне нужно сделать следующее (подход B ):

my $L = aspirin;
beetroot @$L;

Итак, мои вопросы:

  • Почему не работает подход A ?Аргумент на самом деле является ссылкой на массив, чего мы и хотим;
  • Требуется ли разыменование без присваивания (как в подходе B ), требующее копирования всего содержимого списка?(Наверное, нет, поскольку явной копии нет).

Спасибо за ваши ответы

Ответы [ 2 ]

6 голосов
/ 05 января 2012

Прототип \@ не означает ссылку на массив.Это значит, дайте мне массив, но я получу ссылку на него в качестве аргумента (см. perldoc perlsub.

Цитата:

Любой символ прототипа с обратной косой чертой представляет фактический аргумент, которыйобязательно должен начинаться с этого символа. Значение, переданное как часть @_, будет ссылкой на фактический аргумент, указанный в вызове подпрограммы, полученный путем применения "\" к этому аргументу.

Илидругими словами, не используйте прототипы , если вы действительно не знаете, что они делают.

1 голос
/ 05 января 2012

Существуют прототипы Perl для изменения поведения синтаксического анализатора, что редко требуется. Это не исключение.

Если "beetroot" не имеет других аргументов, вам следует просто использовать @_ вместо ссылки на массив.

sub aspirin {
    my @items = qw'some items in here';
    return @items if wantarray; # return a list in list context
    return \@items;
}

sub beetroot {
    print "$_\n" for @_;
}

my $L = aspirin;
beetroot @$L;

# the follow examples require the version of aspirin from this answer

my @L = aspirin;
beetroot @L;

beetroot aspirin; # aspirin called in list context

Это даст дополнительное преимущество: вам не нужно обходить синтаксический анализатор, если вы просто хотите ввести список элементов.

Это работает на новой версии, но не на версии, о которой идет речь.

beetroot qw'some items in here';
beetroot aspirin; # aspirin called in list context

Чтобы заставить его работать с тем, который в вопросе, вы должны создать анонимный массив. Интересно, что это также работает с версией в этом ответе.

beetroot @{ [qw'some items in here'] };
# the follow examples use the version of aspirin from this answer
beetroot @{ [aspirin] };
beetroot @{ scalar aspirin };
beetroot @{ aspirin };

Если вы действительно хотите, чтобы "beetroot" работал с ссылками на массивы. Я бы написал это так.

sub beetroot{
  my($lst) = @_; # similar to my $lst = shift
  print "$_\n" for @$lst;
}

my $L = aspirin;
beetroot $L;

my @L = aspirin; # using the aspirin from this answer
beetroot \@L;

beetroot [qw'some items in here'];
# the follow examples use the version of aspirin from this answer
beetroot scalar aspirin; # force aspirin to return an array reference
beetroot [ aspirin ]; # copy the array

Я бы написал так только в том случае, если вы хотите использовать ссылки для уменьшения объема памяти Perl или если у вас есть другие входные данные до "beetroot".

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