39

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

参照によって渡す必要があることを付け加えておきます。

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

9 に答える 9

68

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

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} を渡す/返すにはどうすればよいですか? も参照してください。

于 2009-04-29T19:20:45.830 に答える
17

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

#!/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' (私の例では)、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 ではなく) ハッシュにマップすることです。同様に、 [ ... ] は配列ではなく配列参照を生成します。

実際、次のように「メイン」コードを変更します。 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.
于 2009-04-29T19:26:47.297 に答える
12

または:

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

あなたが根本的に見逃しているのは、連想配列が単一の引数ではないということです(連想配列参照は、ポール・トンブリンの答えのように)。

于 2009-04-29T19:22:45.980 に答える
4

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

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

PrintAA($foo, \%bar);

あなたができない理由

my %aa = shift;

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

于 2009-04-29T19:22:17.137 に答える
4

いつものように、いくつかの方法があります。以下は、スタイル ポインターの中で最も尊敬されているPerl のベスト プラクティスが、関数へのパラメーターの受け渡しについて述べていることです。

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

いくつかのコードを表示できると、より便利になる可能性があります。

于 2009-04-29T19:24:42.717 に答える
3

以前の回答のすべての方法が機能しますが、これは常に私が次のようなことをすることを好んだ方法でした:

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

注:コードも少し変更しました。Perl の二重引用符で囲まれた文字列は、実際の string ではなく"$test"値として解釈されるため、それほど多くの s は必要ありません。$test'$test'.

また、プロトタイプがどのように機能するかについても間違っていました。ハッシュを渡すには、次を使用します。

PrintAA("test", %hash);

ハッシュ参照を出力するには、次を使用します。

PrintAA("test", %$ref_to_hash);

もちろん、$ref_to_hashコピーを送信しているため、参照されているハッシュを変更することはできませんが%hash、参照として渡しているため、raw を変更することはできます。

于 2009-04-29T19:47:16.577 に答える
2

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

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

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

そのハッシュへの参照を作成するには:

my $href = \%myhash

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

%$href

だからあなたのサブで:

my $myhref = shift;

keys %$myhref;
于 2009-04-29T19:51:04.290 に答える
1

これまでのところ、ここにある他のすべての返信はかなり複雑に思えます。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「飲み込み」、常に 1 つをキーとして解釈し、次の引数を値として解釈します (すべての要素が使い果たされるまで)。

そのように複数のハッシュを渡すことはできず、ハッシュを最初の引数にすることはできません。そうしないと、すべてを飲み込み、他のすべての引数が割り当てられないままになります。

もちろん、最後の引数として配列に対してもまったく同じことが機能します。ここでの唯一の違いは、配列がキーと値を区別しないことです。それらの場合、残ったすべての引数は値であり、配列にプッシュされます。

于 2015-02-11T15:25:05.707 に答える
0

次のサブを使用して、ハッシュまたはハッシュ参照を取得します-渡されたものは何でも:)

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);
于 2009-04-29T19:49:29.710 に答える