2015-03-30 5 views
0

Я пытаюсь передать параметры в подпрограмму perl и по какой-либо причине внутри подпрограммы параметры выходят пустым.Perl Передача аргументов в подпрограмму не работает

... 
... 
... 
print "Passing arguments $a, $b, $c, $d \n"; 
beforeEnd($a, %b, $c, $d); 

sub beforeEnd() { 
    my ($a, %b, $c, $d) = @_; 
    print "a is $a, b is $b, c is $c, d is $d \n"; 
} 

Результаты печати заявлений дают мне представление о том, что что-то не так. Странная часть? Первые 2 параметра проходят правильно.

> Passing arguments 1, (1,2,3), 2, 3 
> a is 1, b is (1,2,3), c is , d is 

Любая помощь была бы принята с благодарностью.

+0

Вы передаете '% b', но печатаете' $ b'. – Barmar

+0

Переменная списка в присваивании получит все остальные аргументы функции. – Barmar

+0

Если вы хотите передать список, не разлагая его в виде отдельных аргументов, вы должны использовать ссылку на массив. – Barmar

ответ

2

Потому что, когда вы передаете аргументы в или из подпрограммы, любые хэши и массивы разбиты плоские.

Вы назначаете %b, который сожрет любые аргументы.

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

sub test1 { 
    my ($first, @rest, $last) = @_; 

    print Dumper \@rest; 

    print "First = $first, last = $last, rest = @rest\n"; 
} 

sub test2 { 
    my ($first, $second) = @_; 
    print "@$first ; @$second"; 
} 

test1 (1, 2, 3, 4); 
test2 ([1,2], [ 3,4]); 

my @list1 = (1,2,3,4); 
my @list2 = (5,6,7,8); 

test1 (@list1, @list2); 
test2 (\@list1, \@list2); 

Если вы хотите сохранить массивы и хэши нетронутыми, вы должны либо передавать их по ссылке или в качестве последнего аргумента.

Вы также, вероятно, получить предупреждение, если вы включили strict и warnings здесь - что одна из причин, настоятельно рекомендуется - потому $b и %b не то же самое. Вы также получите предупреждение о нечетном количестве заданий:

Odd number of elements in hash assignment at line 5. 
Use of uninitialized value $b in print 
1

Когда аргументы передаются подпрограмме Perl, они сплющиваются в один список, представленный @_. Концептуально это означает, что если вы не передаете ссылки на массивы или хэши, вы «потеряете» некоторые данные. «Lose» не совсем корректно, потому что все данные все еще существуют; это просто не в переменной, которую вы ожидаете. Примером этого может быть:

sub f { 
    my (@a, @b) = @_; 

    say 'a: ' . join(', ', @a); 
    say 'b: ' . join(', ', @b); 
} 
f(qw(1 2 3), qw(a b c)); 

вы получите следующий результат:

a: 1, 2, 3, a, b, c 
b: 

Это происходит потому, что первый массив @a потребляет все значения из @_ и там больше нет слева в хранить в @b. То же самое происходит с хешем в вашей предыдущей подпрограмме. Значения $c и $d хранятся внутри %b. В качестве примера, так как я не могу видеть значения переменных, если вы прошли

beforeEnd(1, (a => 1, b => 2), 'c', 3); 

внутри подлодки, вы получите что-то вроде этого:

$a = 1 
%b = (a => 1, b => 2, c => 3) 
$c = undef 
$d = undef 

Вы можете решить эту проблему, передавая ссылку на ваш хэш% б:

beforeEnd($a, \%b, $c, $d); 
1

Подпрограммы принимают список скаляров как аргументы. Если вы передаете массив или хеш, вместо этого передается содержимое массива или хэша.Это означает, что

f($a, %b, $c, $d) 

такая же, как

f($a, $b_key_1, $b_val_1, $b_key_2, $b_val_2, $b_key_3, $b_val_3, $c, $d); 

Сколько скаляров в @_ должны быть назначены %b? Perl сохраняет его простым и присваивает все остальные скаляры, так

my ($a, %b, $c, $d) = @_; 

на самом деле не отличается от

my $a = $_[0];  # The first argument 
my %b = @_[1..$#_]; # All but the first argument 
my $c; 
my $d; 

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

use Data::Dumper qw(Dumper); 

sub beforeEnd { 
    my ($a, $b, $c, $d) = @_; 
    local $Data::Dumper::Terse = 1; 
    print "a is $a, b is ".Dumper($b).", c is $c, d is $d \n"; 
} 

beforeEnd($a, \%b, $c, $d); 

Off теме комментарии о коде:

  • Вы имели прототип указывает на отсутствие аргументов, как ожидается (), но вы ожидаете четыре. Избавь себя от этого прототипа.

  • Вам следует избегать использования $a и $b в качестве переменных, которые могут возникнуть с sort.

0

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

Нам нужно передать ссылку на хэш (или массив, объект) при передаче аргументов подпрограмме. ... ... ... print "Передача аргументов $ a, $ b, $ c, $ d \ n"; beforeEnd ($ a, \% b, $ c, $ d);

sub beforeEnd() { 
    my ($a, $b, $c, $d) = @_; 
    print "a is $a, b is %$b, c is $c, d is $d \n"; 
} 
Смежные вопросы