Вопрос

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

Добавлю, что его нужно передавать по ссылке.

sub PrintAA
{
    my $test = shift;
    my %aa   = shift;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
        $aa{$_} = $aa{$_} . "+";
    }
}
Это было полезно?

Решение

Передайте ссылку вместо самого хеша.Как в

PrintAA("abc", \%fooHash);

sub PrintAA
{
  my $test = shift;
  my $aaRef = shift;

  print $test, "\n";
  foreach (keys %{$aaRef})
  {
    print $_, " : ", $aaRef->{$_}, "\n";
  }
}

См. также perlfaq7: Как я могу передать/вернуть {Function, FileHandle, Array, Hash, Method, Regex}?

Другие советы

Этот код работает:

#!/bin/perl -w

use strict;

sub PrintAA
{
    my($test, %aa) = @_;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
    }
}

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );

PrintAA("test", %hash);

Ключевым моментом является использование контекста массива в операторе my() в функции.


Что на самом деле делает бизнес с контекстом массива?

Короче говоря, это заставляет его работать правильно.

Это означает, что первое значение в @_ массив аргументов присваивается $test, а остальные элементы присваиваются хешу %aa.Учитывая то, как я это назвал, в файле нечетное количество элементов. @_, поэтому, как только первый элемент будет назначен $test, существует четное количество элементов, которым можно назначить %aa, где первый элемент каждой пары является ключом (в моем примере «aaa», «bbb», «ccc»), а второй — соответствующим значением.

Можно было бы заменить %aa с @aa, и в этом случае массив будет содержать 6 элементов.Также можно было бы заменить %aa с $aa, и в этом случае переменная $aa будет содержать значение «ааа», а остальные значения в @_ будет игнорироваться назначением.

Если вы опустите круглые скобки вокруг списка переменных, Perl откажется компилировать код.Один из альтернативных ответов показал обозначение:

my $test = shift;
my(%aa) = @_;

Это во многом эквивалентно тому, что я написал;разница в том, что после двух my заявления, @_ содержит только 6 элементов в этом варианте, тогда как в единственном my версия, она по-прежнему содержит 7 элементов.

Наверняка есть и другие вопросы ТАК о контексте массива.


На самом деле я спрашивал не о my($test, %aa) = @_; я спрашивал о my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); против my %hash = { 'aaa' => 1, ... };

Разница в том, что {...Нотация } генерирует ссылку на хеш и (...) генерирует список, который отображается в хэш (в отличие от хэша ref).Сходным образом, [ ...] генерирует ссылку на массив, а не массив.

Действительно, измените «основной» код так, чтобы он гласил:мой(%хэш) = { ...};и вы получите ошибку во время выполнения (но не во время компиляции) - относитесь к номерам строк с осторожностью, поскольку я добавил в свой файл альтернативные кодировки:

Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.

Альтернативно:

sub PrintAA
{
    my $test       = shift;
    my %aa         = @_;
        print $test . "\n";
        foreach (keys %aa)
        {
                print $_ . " : " . $aa{$_} . "\n";
                $aa{$_} = $aa{$_} . "+";
        }
}

Чего вам принципиально не хватает, так это того, что ассоциативный массив не является единственным аргументом (хотя ссылка на ассоциативный массив есть, как в ответе Пола Томблина).

Похоже, вам следует передать ссылку на хэш.

sub PrintAA
{
   my $test = shift;
   my $aa = shift;
   if (ref($aa) != "HASH") { die "bad arg!" }
   ....
}

PrintAA($foo, \%bar);

Причина, по которой вы не можете сделать

my %aa = shift;

Причина в том, что Perl объединяет все аргументы подпрограммы в один список @_.Копируется каждый элемент, поэтому передача по ссылке также позволяет избежать этих копий.

Как обычно, есть несколько способов.Вот что Лучшие практики Perl, самый почитаемый из указателей стиля, говорит о передаче параметров функциям:

Используйте хэш именованных аргументов для любой подпрограммы, имеющей более трех параметров.

Но поскольку у вас их только два, вы можете обойтись без них ;) и передать их напрямую следующим образом:

my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);

func($scalar, %hash)

И функция определяется следующим образом:

sub func {
    my $scalar_var = shift;
    my %hash_var = @_;

    ... Do something ...
}

Было бы полезнее, если бы вы показали какой-нибудь код.

Все вышеперечисленные методы работают, но я всегда предпочитал делать такие вещи:

sub PrintAA ($\%)
{
    my $test       = shift;
    my %aa         = ${shift()};
    print "$test\n";
    foreach (keys %aa)
    {
        print "$_ : $aa{$_}\n";
        $aa{$_} = "$aa{$_}+";
    }
}

Примечание:Я также немного изменил ваш код.Строки Perl в двойных кавычках будут интерпретироваться "$test" быть ценностью $test а не фактическая строка '$test', так что вам не нужно так много .с.

Кроме того, я ошибался насчет того, как работают прототипы.Чтобы передать хеш, используйте это:

PrintAA("test", %hash);

Чтобы распечатать ссылку на хеш, используйте это:

PrintAA("test", %$ref_to_hash);

Конечно, теперь вы не можете изменить хэш, на который ссылается $ref_to_hash потому что вы отправляете копию, но можете изменить необработанный файл %hash потому что вы передаете его как ссылку.

Аргументы функций сводятся в один массив (@_).Поэтому обычно проще всего передавать хеши в функцию по ссылке.

Чтобы создать ХЕШ:

my %myhash = ( key1 => "val1", key2 => "val2" );

Чтобы создать ссылку на этот HASH:

my $href = \%myhash

Чтобы получить доступ к этому хешу по ссылке;

%$href

Итак, в вашем сабвуфере:

my $myhref = shift;

keys %$myhref;

Все остальные ответы здесь пока кажутся мне довольно сложными.Когда я пишу функцию Perl, я обычно «расширяю» все переданные аргументы в первой строке функции.

sub someFunction {
    my ( $arg1, $arg2, $arg3 ) = @_;

Это похоже на другие языки, где вы объявляете функции как

... someFunction ( arg1, arg2, arg3 )

И если вы сделаете это таким образом и передадите хеш в качестве последнего аргумента, все будет в порядке без каких-либо уловок или особой магии.Например.:

sub testFunc {
    my ( $string, %hash ) = @_;
    print "$string $hash{'abc'} $hash{'efg'} $string\n";
}

my %testHash = (
    'abc' => "Hello",
    'efg' => "World"
);
testFunc('!!!', %testHash);

Результат ожидаемый:

!!! Hello World !!!

Это работает, потому что в Perl аргументы всегда передаются как массив скалярных значений, и если вы передаете хеш, его ключевое значение/пары добавляются к этому массиву.В приведенном выше примере аргументы передаются функции в виде массива (@_) на самом деле:

'!!!', 'abc', 'Hello', 'efg', 'World'

и '!!!' просто назначен %string, пока %hash «проглатывает» все остальные аргументы, всегда интерпретируя один как ключ, а следующий как значение (пока все элементы не будут израсходованы).

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

Конечно, то же самое работает и с массивом в качестве последнего аргумента.Единственная разница здесь в том, что массивы не различают ключи и значения, для них все оставшиеся аргументы являются значениями и просто помещаются в массив.

Используйте следующую подпрограмму, чтобы получить хэш или хэш-ссылку — что бы ни прошло :)

sub get_args { ref( $_[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
  my $test = shift;
  my $aa = get_args(@_);;
  #then
  $aa->{somearg} #do something
  $aa->{anotherearg} #do something

}

Вызовите свою функцию следующим образом:

printAA($firstarg,somearg=>1, anotherarg=>2)

Или вот так (неважно):

printAA($firstarg,{somearg=>1, anotherarg=>2})

Или даже так (неважно):

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );

PrintAA("test", %hash);

Ваше здоровье!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top