Как я могу передать два массива и строку в подпрограмму Perl? - PullRequest
10 голосов
/ 21 октября 2010

Как я могу передать два массива и строку в подпрограмму?

Вот что я пытаюсь сделать:

use strict;
use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE);
my @y = qw(1111 2222 3333 4444 5555);

my $z = "hello";

Hello(@x,@y,$z);

exit(0);

sub Hello {

    my (@x,@y,$z) = @_;

    print "$_\n" for @x;
    print "$_\n";
    print "$_\n" for @y;
    print "$_\n";
    print "$z\n";
}

Вывод:

AAA
BBBB
CCCC
DDDD
EEEE
1111
2222
3333
4444
5555
hello
Use of uninitialized value $_ in concatenation (.) or string at test.pl line 19.

Use of uninitialized value $_ in concatenation (.) or string at test.pl line 21.

Use of uninitialized value $z in concatenation (.) or string at test.pl line 22.

Ответы [ 4 ]

15 голосов
/ 21 октября 2010

Вам необходимо передать каждый из массивов как ссылку, иначе ваш @x в подпрограмме сожрет ВЕСЬ массив аргументов, оставив @y пустой массив и $z неопределенное значение.

Это происходит потому, что оператор запятой - в контексте списка - превратит @x, @y, $z в один массив, состоящий из всех элементов @x, за которыми следуют все элементы @y а затем значение $z;@x в подпрограмме сожрет ВЕСЬ объединенный массив аргументов, оставив @y пустой массив и $z неопределенное значение.

Другим возможным источником путаницы является тот факт, что вы назвали обапеременные @x, несмотря на то, что они полностью независимы друг от друга из-за правил области видимости.Хорошей практикой будет называть их чем-то уникальным, чтобы избежать угадывания того, какой из них вы хотели использовать, например, вызовите первый массив подпрограммы @x2.

Обратите внимание, что вы можете передать массив как ссылку в одиндвух способов - ссылка на исходный массив (реальный метод передачи по ссылке), а также ссылка на копию массива - который будет вести себя так, как вы хотели, чтобы ваш исходный код вел себя и передавался по значению.

use strict; use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE); 
my @y = qw(1111 2222 3333 4444 5555);
my $z = "hello";

Hello(\@x,\@y,$z);

# If you wish to pass a reference of a COPY of the array, 
# so that you can modify it inside the subroutine without modifying the original,
# instead call Hello([@x], [@y], $z);

exit(0);

sub Hello {

    my ($x2,$y2,$z2) = @_;
    # Now, you de-reference array reference $x2 via @$x2 or $x2->[$i]
    # where previously you used @x2 or $x2[$i]
    print "$_\n" for @$x2;
    print "$_\n";
    print "$_\n" for @$y2;
    print "$_\n";
    print "$z2\n";

}
8 голосов
/ 21 октября 2010

вам нужно использовать ссылки:

sub Hello {
   my ($x, $y, $z) = @_;
   print "$_\n" for @$x;
   ...
}

Hello(\@x, \@y, $z);

вы также можете использовать прототипы подпрограмм Perl для устранения \ на сайте вызовов:

sub Hello (\@\@$) {...}

Hello(@x, @y, $z);

Прототип (\@\@$) сообщает компилятору, что аргументы Hello будут иметь контекст ссылки на массив в первых двух аргументах и ​​скалярный контекст в третьем аргументе. Прототипы не предназначены для проверки аргументов, они позволяют вам писать подпрограммы, которые работают как встроенные. В этом случае, как push.

Как отмечает DVK в комментарии ниже, PBP рекомендует не использовать прототипы как общее правило, поскольку они, как правило, используются ненадлежащим образом для проверки аргументов. Мне кажется, что использование определенных функций прототипов (\% или \@ для наложения ссылочного контекста для множественных типов, или & в качестве первого аргумента, разрешающего map подобный синтаксису блока) оправдывает разрыв с PBP. Особенно верно, если sub используется для расширения синтаксиса Perl (вспомогательные функции, функции, которые являются просто синтаксическим сахаром ...)

3 голосов
/ 21 октября 2010

Вам необходимо передать ссылки на массив:

sub Hello {
  my ( $x_ref, $y_ref, $z ) = @_;
  my @x = @$x_ref;
  my @y = @$y_ref;
  ...
}

Hello( \@x, \@y, $z );
1 голос
/ 21 октября 2010
use strict; use warnings;

my @x = qw(AAAA BBBB CCCC DDDD EEEE); my @y = qw(1111 2222 3333 4444 5555);

my $z = "hello";

Hello(\@x,\@y,$z);

exit(0);

sub Hello {
    my ($x,$y,$z) = @_;

    print "$_\n" for @$x;
    print "$_\n" for @$y;
    print "$z\n";

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