web-dev-qa-db-ja.com

Perlの関数にハッシュを渡すにはどうすればよいですか?

変数と連想配列を受け取る関数がありますが、それらを正しく渡すことができないようです。これは関数宣言と関係があると思いますが、Perlでどのように機能するかはわかりません。これについての良いリファレンスはありますか?また、どうすれば必要なことを達成できますか?

参照渡しする必要があることを追加する必要があります。

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

ハッシュ自体の代わりに参照を渡します。のように

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}を渡す/返すにはどうすればよいですか?

67
Paul Tomblin

このコードは機能します:

#!/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() 'statement'で配列コンテキストを使用することです。


アレイコンテキストビジネスは実際に何をしていますか?

簡潔に言うと、正しく動作します。

これは、引数の@_配列の最初の値が$testに割り当てられ、残りの項目がハッシュ%aaに割り当てられることを意味します。私がそれを呼び出した方法を考えると、@_には奇数のアイテムがあるので、最初のアイテムが$testに割り当てられると、%aaに割り当てることができる偶数のアイテムがあり、各ペアの最初のアイテムはキー(この例では「aaa」、「bbb」、「ccc」)、2番目は対応する値です。

%aa@aaに置き換えることが可能です。この場合、配列には6つのアイテムが含まれます。 %aa$aaに置き換えることも可能です。その場合、変数$aaには値 'aaa'が含まれ、@_の残りの値は割り当てによって無視されます。

変数リストの括弧を省略すると、Perlはコードのコンパイルを拒否します。別の回答の1つは表記法を示しました。

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

これは、私が書いたものとほとんど同じです。違いは、2つのmyステートメントの後、@_にはこのバリエーションでは6つの要素しか含まれていないのに対し、単一のmyバージョンでは、まだ7つの要素が含まれています。

[〜#〜] so [〜#〜] には配列コンテキストに関する他の質問が間違いなくあります。


実際、私はmy($test, %aa) = @_;について尋ねていませんでしたmy(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );my %hash = { 'aaa' => 1, ... };について尋ねていました

違いは、{...}表記がハッシュrefを生成し、(...)表記がハッシュ(ハッシュrefではなく)にマップするリストを生成することです。同様に、[...]は配列ではなく配列refを生成します。

実際、次のように「メイン」コードを変更します。my(%hash)= {...};実行時(コンパイル時ではない)エラーが発生します-ファイルに代替コーディングを追加したため、行番号を慎重に扱ってください。

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.
16

代わりに:

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

基本的に不足しているのは、連想配列が単一の引数ではないことです(ただし、Paul Tomblinの答えのように、連想配列参照はあります)。

12
chaos

ハッシュへの参照を渡す必要があるようです。

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

PrintAA($foo, \%bar);

できない理由

my %aa = shift;

perlがサブルーチンへのすべての引数を1つのリスト@_にフラット化するためです。すべての要素がコピーされるので、参照で渡すと、それらのコピーも回避されます。

4
mkb

いつものように、いくつかの方法があります。ここに、Perl Best Practicesというスタイルポインターが最も尊敬されており、関数にパラメーターを渡すことについて述べなければならないものがあります。

3つ以上のパラメーターを持つサブルーチンには、名前付き引数のハッシュを使用します

ただし、2つしかないため、次のように直接渡すことで逃げることができます;)

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 ...
}

何らかのコードを表示できれば、さらに便利です。

4
Ya. Perelman

上記のすべての方法は機能しますが、これは常にこのようなことをすることを好む方法でした:

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を変更することができます。

3
Chris Lutz

関数の引数は、単一の配列(@_)にフラット化されます。そのため、通常はハッシュを参照により関数に渡すのが最も簡単です。

ハッシュを作成するには:

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

そのHASHへの参照を作成するには:

my $href = \%myhash

そのハッシュに参照でアクセスするには;

%$href

あなたのサブで:

my $myhref = shift;

keys %$myhref;
1
Arnshea

次のサブを使用して、hashまたはhashrefを取得します-渡されたものは何でも:)

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);

乾杯!

0
Беров